【Java】多线程

多线程

有了多线程,可以让程序同时做多件事情

并发:多个指令在单个CPU交替执行

并行:多个指令在多个CPU同时执行

实现方法

1)继承Thread类的方式

  1. 自己定义一个类继承Thread
  2. 编写run方法
  3. 创建子类对象,并启动线程

Main类

public class Main {
    public static void main(String[] args) {
        Test test1=new Test();
        Test test2=new Test();

        test1.start();
        test2.start();
    }
}

线程类

public class Test extends Thread{
    static int n=10;

    @Override
    public void run() {
        for (; n >= 0; n--) {
            System.out.println(n);
        }
    }
}

2)继承Runnable接口的方式

  1. 自己定义一个类实现Runnable接口
  2. 重写run方法
  3. 创建自定义的对象
  4. 创建一个Thread类对象,传入自定义类

Main类

public class Main {
    public static void main(String[] args) {
        Test test=new Test();
        Thread thread1=new Thread(test);
        Thread thread2=new Thread(test);

        thread1.start();
        thread2.start();
    }
}

自定义类

public class Test implements Runnable{
    static int n=10;

    @Override
    public void run() {
        for (; n >= 0; n--) {
            System.out.println(n);
        }
    }
}

3)利用Callable接口和Future接口的方式

  1. 创建一个自定义类实现Callable接口
  2. 重写call有返回值的,表示多线程的运行结果。前面两种方法的run方法的放回值都是void
  3. 创建自定义类的对象(表现多线程要执行的人物)
  4. 创建FutureTask的对象(管理多线程运行的结果)
  5. 创建Thread对象,传入FutureTask的对象

Main类

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Test test=new Test();
        FutureTask<Boolean> futureTask=new FutureTask<>(test);
        Thread t1=new Thread(futureTask);
        t1.start();
        
        boolean result=futureTask.get();
        System.out.println(result);
    }
}

线程类

import java.util.concurrent.Callable;

public class Test implements Callable<Boolean> {
    static int n = 10;

    @Override
    public Boolean call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
        return true;
    }
}

Callable的泛型类型就是返回值类型

三种实现方法的对比

  1. 继承Thread类的方式
    • 简单性:相对简单,不需要实现**run方法,可以直接覆盖Thread类的run**方法。
    • 可扩展性:有限,因为Java不支持多重继承,如果已经继承了**Thread**类,就不能再继承其他类。
    • 资源共享:相对较难在多个线程之间共享资源,因为每个线程都有自己的状态和上下文。
    • 适用场景:适用于简单的线程创建和管理,例如执行独立的任务。
  2. 继承Runnable接口的方式
    • 简单性:相对简单,需要实现**run**方法,可以实现其他接口和继承其他类。
    • 可扩展性:更好,因为可以实现其他接口和继承其他类,更加灵活。
    • 资源共享:更容易在多个线程之间共享资源,因为多个线程可以共享相同的**Runnable**实例。
    • 适用场景:适用于需要多个线程执行相同任务,或者需要资源共享的情况。
  3. 利用Callable接口和Future接口的方式
    • 返回值:支持有返回值的多线程任务,通过**FutureTask**可以获取线程执行结果。
    • 简单性:相对复杂,因为需要实现**Callable接口和处理FutureTask**。
    • 可扩展性:较好,可以使用泛型灵活处理不同类型的返回值。
    • 资源共享:与继承**Runnable**方式类似,可以共享资源。
    • 适用场景:适用于需要获取线程执行结果的复杂场景,例如多线程任务池。

Thread类方法

String getName()                          返回此线程的名称
void setName()                            设置此线程的名称(也可以使用构造方法)
static Thread currentThread()             获取当前线程的对象
static void sleep(long time)              让线程休眠指定的时间,单位为毫秒
setPriority(int newPriority)              设置线程优先级
final int getPriority()                   获取线程优先级
final void setDaemon(boolean on)          设置为守护线程
public static void yield()                出让/礼让线程
public static void join()                 插入线程/插队线程

方法细节

  1. 在使用extend实现线程的方法中,书写自定义类的时候要把super代码一起写,要不然无法调用父类Thread的方法
  2. sleep方法
    • 1秒=1000毫秒
  3. setPriority方法
    • 可以设置的优先级范围为1-10,没有设置默认为5
  4. setDaemon守护线程方法
    • 当所有非守护线程都结束时,守护线程会随之结束

线程的生命周期

【Java】多线程_第1张图片

sleep()获取醒来后是要去重新获取CPU的执行权的,但是获取到了执行权,他不是从run方法从头开始执行,而是从刚刚的sleep代码下面开始执行

线程锁

synchronized

同步代码块

直接像if方法一样用synchronized把代码括起来

synchronized(锁对象){...}
什么东西都可以当锁对象,但是一定要是唯一的

同步方法

格式:修饰符 synchronized 返回值类型 方法名(方法参数)

  1. 同步方法锁住方法里面所有的代码
  2. 锁的对象不能自己指定
    • 非静态:this
    • 静态:当前类的字节码文件(静态方法中没有this)

lock

  1. 创建锁对象:static Lock *lock*=new ReentrantLock();
  2. 上锁:lock.lock()
  3. 释放锁:lock.unlock()

生产者和消费者模式(包括阻塞队列)

指路

多线程必考的「生产者 - 消费者」模型,看齐姐这篇文章就够了-阿里云开发者社区

线程池

  1. 创建一个池子,池子中是空的
  2. 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子。下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
  3. 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待

代码实现

Executors:线程池的工具类通过调用方法返回不同类型的线程池对象

你可能感兴趣的:(java,开发语言)