Thread类中的枚举类State展示了Java线程的六种状态,线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:
thread.start():线程对象thread刚创建时状态为NEW,在调用start()方法后进入RUNNABLE状态开始运行,等待系统调度获得CPU时间片,线程这时候处于 READY(可运行) 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 RUNNING(运行) 状态。
在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态
object.wait():当前线程释放对object对象的锁,并使当前线程从RUNNABLE状态进入WAITING状态,进入到该对象的等待池中,等待池中的线程不会去竞争对象锁。
object.wait(mills):当前线程释放对object对象的锁,使当前线程从RUNNABLE状态进入TIME_WAITING状态,超时等待。当超时时间结束后,并进入该对象的锁池中,锁池中的线程会去竞争该对象锁。
当线程结束等待状态进入锁池竞争锁时,若竞争失败则会进入BLOCKED状态,只有在获得锁后才会重新回到到RUNNABLE状态继续执行下去。
object.notify():当前线程释放对object对象的锁,并随机从该对象的等待池中唤醒一个线程从等待状态进入运行状态,被唤醒的的线程会进入该对象的锁池中。
object.notifyAll():当前线程释放对object对象的锁,并唤醒该对象的等待池中的所有线程进入该对象的锁池中。
wait()方法和notify()方法都只能在synchonized代码中调用,否则运行时会报非法监视器状态异常(llegalMonitorStateException),道理也很简单,首先你得持有锁才能释放锁。
参考:
- wait会释放锁?当然会释放锁,代码见真招
- java中的notify和notifyAll有什么区别?
Thread.sleep(mills):静态方法,暂停当前线程(不会释放锁),使线程从RUNNABLE状态进入TIME_WAITING状态,超时等待。当超时时间结束后,线程将会返回到 RUNNABLE 状态。
thead.join():使当前线程获取thead对象的锁,然后调用thead.wait()使当前线程进入等待状态,进入thead对象的等待池,当thead线程执行完毕时会notifyAll唤醒所有thead对象等待池中的线程,这就包括了当前线程,使当前线程回到当前线程继续执行下去。
thread.join(mills):同上,只不过是超时等待,超时结束后进入thead对象锁池。
join()方法的底层原理:
当thread对象的run方法执行结束后,会notifyAll唤醒所有thead对象等待池中的线程。
参考:Java 多线程join()方法的作用和实现原理解析
thread.yield():使处于RUNNABLE状态的thread线程回到就绪状态,重新等待CPU调度运行。
thread.interrupt():当前线程给thread线程设置一个中断标志位。关于这个方法的理解如下:
参考:对Thread.interrupt()的理解
以下为一个简单的生产者-消费者模型案例
生产者:多个生产者线程并发生产消息放入队列中,每生产一个消息都唤醒所有消费者线程,队列有最大长度,当队列满则生产者线程进入等待状态。
消费者:多个消费者线程从队列中取消息,当队列为空则消费者线程进入等待状态,并唤醒所有生产者线程进行生产。
//生产者-消费者队列
public class WaitNotifyQueue {private final LinkedList queue = new LinkedList<>();private final static int MAX_COUNT = 10;//队列最大长度public synchronized void put(T resource) throws InterruptedException {while (queue.size() >= MAX_COUNT) {//队列满了,不能再塞东西了,轮询等待消赉者取出数据System.out.println("生产者:队列已满,无法插入...");this.wait();}System.out.println("生产者:插入"+resource + "! ! !");queue.addFirst(resource);this.notifyAll();}public synchronized void take() throws InterruptedException {while (queue.size() <= 0) {//队列空了,不能再取东西,轮询等待生产者插入数据System.out.println("消费者:队列为空,无法取出...");this.wait();}System.out.println("消费者:取出消息! !!");queue.removeLast();this.notifyAll();}
}class Test {public static void main(String[] args) {WaitNotifyQueue waitNotifyQueue = new WaitNotifyQueue<>();//生产者线程 可多个new Thread(() -> {for (int i = 0;i<100;i++) {try {waitNotifyQueue.put("消息" + Thread.currentThread().getName() + i);//生产} catch (InterruptedException e) {e.printStackTrace();}}}).start();//消费者线程 可多个new Thread(() -> {for (int i = 0;i<100;i++) {try {waitNotifyQueue.take();//消费} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}
参考: