进入正题前需要了解的概念
-
Java中的线程的状态分为6种。
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
- 运行(RUNNABLE):Java线程准备就绪(ready)和运行中(running)两种状态笼统的成为“运行”。 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得cpu 时间片后变为运行中状态(running)。
- 阻塞(BLOCKED):表线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIME_WAITING):该状态不同于WAITING,它可以在指定的时间内自行返回。
- 终止(TERMINATED):表示该线程已经执行完毕。
-
锁与监视器的区别
- JVM为每一个对象和类都关联一个锁,锁住了一个对象,就是获得对象相关联的监视器。
- 当声明 synchronized 的代码块时,编译而成的字节码会包含一个监视器和多个监视器退出路径 (多个退出路径,正常和异常情况),当执行被锁的代码时,检查目标锁对象的计数器是否为0,如果为0则将锁对象的持有线程设置为自己,然后计数器加1,获取到锁,如果不为0则检查锁对象的持有线程是不是自己,如果是自己就将计数器加1获取锁,如果不是则阻塞等待,退出的时候计数器减1,当减为0的时候清楚锁对象的持有线程标记。(可以看出 synchronized 是支持可重入的)
- 逻辑上锁是对象内存堆中头部的一部分数据。JVM中的每个对象都有一个锁,任何程序都可以使用它来协调对对象的多线程访问。如果任何线程想要访问该对象的实例变量,那么线程必须拥有该对象的锁(在锁内存区域设置的标志)。所有其他的线程试图访问该对象的变量,必须等到拥有该对象的锁有的线程释放锁(改变标记)。
- 监视器是任何一个对象都有的内置的同步数据结构,它是用来协调有多个线程调用当前对象的时的执行顺序,线程会block或者wait 在一个对象的监视器上,可理解为监视器确保只有一个线程访问共享资源,所有期待获得锁的线程,在锁已经被其它线程拥有的时候,这些期待获得锁的线程就进入了监视器的entry set区域。所有曾经获得过锁,但是由于其它必要条件不满足而需要wait的时候,线程就进入了监视器的wait set区域 。在wait set区域的线程获得Notify/notifyAll通知的时候,随机的一个Thread(Notify)或者是全部的Thread(NotifyALL)从监视器的wait set区域进入了entry set中。在当前拥有锁的线程释放掉锁的时候,处于该监视器的entryset区域的线程都会抢占该锁,但是只能有任意的一个Thread能取得该锁,而其他线程依然在entry set中等待下次来抢占到锁之后再执行。
- 所以,监视器实际上就是实现synchronized锁的具体实现方法
-
jdk文档中的描述
- wait:当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用
notify
方法,或notifyAll
方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。 - notify:唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个
wait
方法,在对象的监视器上等待。直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。 - notifyAll:唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个
wait
方法,在对象的监视器上等待。直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。
package test;public class Test1 { private static Object[] objs = new Object[10]; public static void main(String[] args) { Runnable run1 = new Runnable() { @Override public void run() { synchronized (objs) { try { System.out.println(1); objs.wait(); System.out.println(2); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Runnable run2 = new Runnable() { @Override public void run() { synchronized (objs) { System.out.println(3); objs.notify(); } } }; new Thread(run1).start(); new Thread(run2).start(); }}运行结果132