一、notify的含义(视为使当前线程获取对象锁并于规定一定条件下释放的方法)
(1)notify一次只随机通知一个线程进行唤醒(notifyAll则为全部)
(2) 在执行了notify方法之后,当前线程不会马上释放该对象锁,呈wait状态的线程也不能马上获得该对象锁,
要等到执行notify方法的线程将程序执行完 ,也就是退出sychronized代码块后,当前线程才会释放锁,
而呈wait状态所在的线程才可以获取该对象锁。
对象锁释放的三种情况
序号场景
1、执行完同步代码块就会释放对象的锁
2、在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放
3、在执行同步代码块的过程中,执行了锁所属对象的wait方法,这个线程会提前释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒(阻塞),直到等到到下一个notify将锁给他,才开始执行最后一个wait后面剩余的代码。
二,wait的含义(视为使当前线程马上释放对象锁并阻塞的方法)
(1)将当前进程挂起,等待唤醒
(2)wait( )会先释放锁住的对象,然后再执行挂起的动作。参见以上第3点
三、为什么wait方法与notify方法要用synchronized保证同步
1. 正如Java内任何对象都能成为锁(Lock)一样,任何对象也都能成为条件队列(Condition queue)。而这个对象里的wait(), notify()和notifyAll()则是这个条件队列的固有(intrinsic)的方法。
2.一个对象的固有锁和它的固有条件队列是相关的,为了调用对象X内条件队列的方法,你必须获得对象X的锁。这是因为等待状态条件的机制和保证状态连续性的机制是紧密的结合在一起的。
根据上述两点,在调用wait(),
notify()或notifyAll()的时候,必须先获得锁,且状态变量须由该锁保护,而固有锁对象与固有条件队列对象又是同一个对象。也就是说,要在某个对象上执行wait,notify,先必须锁定该对象,而对应的状态变量也是由该对象锁保护的。
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。以下实例:定义两个线程轮流分别输出0~99之间的所有数;
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中。如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
解析:由于输出对象是单纯的对象,所以不需要将其封装成另一个资源类,在同一个run方法中输出即可;
以下是线程方法的测试,分几轮进行说明:
http://www.cnblogs.com/techyc/p/3272321.html
http://blog.csdn.net/lingzhm/article/details/44940823