Thread概述
从Thread声明上看,Thread实现了Runnable接口
- 定义:一个
Thread
指的是一个程序的执行线程。Java虚拟机支持一个应用程序同时并发执行多个线程。 - 优先级:每个线程都有优先级。当创建新线程时,新线程的优先级与原线程相同。
- 优先级从1到10,表示从低到高,5为默认优先级
- daemon:每个线程都可以被标记为
daemon
(守护线程/后台线程),后台线程创建的新线程仍然是后台线程。 - 线程名称:每个线程都有一个名称用来标识,名称可以重复,当未指定时会自动生成名称。
创建新线程的方法
- 继承
Thread
类,重写Run方法,通过start调用
MyThread p=new MyThread();
p.start();
- 实现
Runnable
类,实现唯一的Run方法,通过Thread传参调用
MyRunnable p=new MyRunnable();
new Thread(p).start();
Runnable概述
- Runnable是什么:
Runnable是一个函数式的接口,其中只有一个Run方法。
- Runnable怎么用:
Runnable用于任何想要被线程执行的对象所属的类,这个类必须实现Run方法。
- 为什么设计Runnable接口:
Runnable设计的目的是为所有想要在active状态时执行代码的对象所提供通用的协议。
active状态的意思仅为线程启动且未被终止
另外,Runnable的设计使得类在需要active时无需继承Thread,毕竟继承的用途仅为需要拓展或修改父类功能时使用。
因此,Runnable的用途通常为,设计的类仅需要重写Run方法而不希望重写Thread其他方法,即继承Thread。
- Run方法的作用
当一个实现了Runnable接口的对象被Thread线程启动时,启动这个线程将会使得Run方法被调用。
Run方法可以执行任何操作。
Thread源码
CurrentThread()
- 方法定义:
static native CurrentThread()
CurrentThread方法返回当前线程对象,注意这个方法是一个静态的、native的方法。
native关键字:native关键字常在源码中出现,表示该方法不是使用Java代码实现的,没有方法体。一个native方法就是调用非Java方法的接口。而内存中会有专门开辟的区域: Native Method Stack,用于登记Native方法
start()
-
当主线程调用start方法时,Java虚拟机将对该Thread类的run()方法进行调用,产生新的线程,此时新线程和主线程并发执行。
-
一个线程只能被调用一次,且执行后不能被重新启动(restart)
-
被synchronized修饰,调用native的start方法,由操作系统创建线程
run()
- Run方法内会判断类型为Runnable的target判断是否为空
- 如果未被重写,则什么都不做直接返回
wait()
- 注意,线程必须拥有当前对象的锁才能调用wait()方法
- 拥有锁的方法:使用synchronized关键字修饰对象,其将保证只有进入synchronized修饰范围的线程获得当前对象的监视器
- wait()方法将造成当前线程处于等待状态,并释放线程获得的锁,直到另外一个拥有该对象的监视器monitor的线程调用notify/all方法进行唤醒。
- wait被唤醒的四种情况:
- 其他线程调用了这个对象的notify方法,并且当前线程恰好被选择唤醒
- 其他线程调用了这个对象的notifyAll方法
- 其他线程中断(interrupts)了当前线程
- 超时时间过期
- 虚假唤醒 线程也会在未被上述情况唤醒的情况下自动唤醒,因此使用wait()方法时应该放在循环里,当不满足唤醒条件时,循环继续进入wait()中
- 调用notify/all会让所有处于等待锁(监视器)状态的线程尝试获得锁
- wait(time) 表示等待的超时时间,超过该时间还没有被唤醒时,则尝试重新获取对象的锁,
- wait(0)与wait()一样,表示一直等待
- 不论是正常退出synchronized还是异常,Java为每一个出口都设置了释放,外面都会再调用一次monitorexit,保证正常释放锁
监视器:可以将监视器想象为一个门禁系统。当一个线程进入同步代码块时,它会获得该对象的监视器(锁),就像获得了门禁系统的许可。在同一时刻,只有获得许可的线程可以进入同步代码块执行操作,其他线程必须等待。当线程离开同步代码块时,它释放了监视器(锁),就像离开了门禁系统的区域,其他线程可以继续进入。
需要注意的是,获取对象的监视器不仅仅是获取对象的锁,还包括了一些额外的信息,比如等待队列和通知机制,用于实现线程间的协作和通信。
sleep()
- 调用sleep方法,当前线程休眠一段时间
- 不会释放当前对象的锁(monitor)