多线程

多线程的概念

多线程是一种用于实现并发执行的计算机编程技术,这允许单个程序创建和管理多个线程,以同时执行多个任务或执行块。

  • 并发:在同一时刻,有多个指令在单个CPU上交替执行
  • 并行:在同一时刻,有多个指令在CPU上同时执行

线程的生命周期

  • 新建(New):创建后尚未启动的线程处于这个状态
  • 就绪(Runnable):调用start()方法后,线程进入就绪状态,此时线程只是开辟了内存空间,正在等待被线程调度器选中获得对CPU的使用权
  • 运行(Running):线程获得CPU权限进行执行
  • 阻塞(Blocked):线程因为某些原因放弃CPU使用权,暂时停止运行,直到线程进入就绪状态才有机会转到运行状态
  • 死亡(Terminated):线程执行结束或者因为异常退出的状态

多线程的实现方式

  • 继承Thread类的方式进行实现
    • 自己定义一个类继承Thread
    • 重写run方法
    • 创建子类对象,并启动线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//定义一个类继承Thread
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName());
}
}
}
//开启线程
public class Main {
public static void main(String[] args) {
创建MyThread对象
MyThread t1 = new MyThread();
//设置线程名字
t1.setName("线程1");
//可以合并写:
//MyThread t1 = new MyThread("线程1")
//开启线程
t1.start();
}
}
  • 实现Runnable接口的方式进行实现
    • 自己定义一个类实现Runnable接口
    • 重写run方法
    • 创建自己定义的类的对象
    • 创建一个Thread类的对象,并开启线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//定义一个类实现Runnable接口
public class MyRun implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
//获取到当前线程的对象
Thread t = Thread.currentThread();
System.out.println(t.getName());
}
}
}
//开启线程
public class Main {
public static void main(String[] args) {
//创建MyRun对象
MyRun mr = new MyRun();
//创建线程对象
Thread t1 = new Thread(mr);
//给线程设置名字
t1.setName("线程1");
//开启线程
t1.start();
}
}
  • 利用Callable接口和Future接口方式实现
    • 特点:可以获取多线程运行的结果
    • 自己定义一个类实现Callable接口
    • 重写call(有返回值,表示多线程运行的结果)
    • 创建自己定义的类的对象(表示多线程要执行的任务)
    • 创建FutureTask的对象(管理多线程运行的结果)
    • 创建Thread类的对象,并启动(表示线程)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}
}

public class Main {
public static void main(String[] args) {
//创建MyCallable对象(表示多线程要执行的任务)
MyCallable mc = new MyCallable();
//创建FutureTask对象(管理多线程运行的结果)
FutureTask<Integer> ft = new FutureTask<> (mc);
//创建线程的对象
Thread t1 = new Thread(ft);
//启动线程
t1.start();
//获取多线程运行的结果
Integer result = ft.get();
System.out.println(result);
}
}

三种实现方式的比较

优点 缺点
继承Thread类 编程比较简单,可以直接使用Thread类中的方法 可以扩展性较差,不能再继承其他类
实现Runnable接口 扩展性强,实现该接口的同时还可以继承其他的类 编程相对复杂,不能直接使用Thread类中的方法
实现Callable接口 扩展性强,实现该接口的同时还可以继承其他的类 编程相对复杂,不能直接使用Thread类中的方法

多线程中常用的成员方法

  • 返回此线程的名称

String getName()

  • 设置线程的名字(构造方法也可以设置名字)

void setName(String name)

  • 获取当前线程的对象

当JVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程,它的作用就是去调用main方法,并执行里面的代码

static Thread currentThread()

  • 让线程休眠指定的时间,单位为毫秒

static void sleep(long time)

  • 设置线程的优先级

1 -> 最小

10 -> 最大

5 -> 默认

setPriority(int newPriority)

  • 获取线程的优先级

final int getPriority()

  • 设置守护线程

当其他的非守护线程完毕之后,守护线程回陆续结束

final void setDaemon(boolean on)

  • 出让线程/礼让线程

public static void yield()

  • 插入线程/插队线程

public static void join()

等待唤醒机制

  • 当前线程等待,直到被其他线程唤醒

void wait()

  • 随即唤醒单个线程

void notify()

  • 唤醒所有线程

void notifyAll()