需要注意的是:调用sleep()和yield()的时候锁并没有被释放,而调用wait()将释放锁
另外需要注意的是,wait()和notify()只能在synchronized方法或者synchronized块中使用
notify()通知等待队列中的第一个线程,notifyAll()通知的是等待队列中的所有线程
下面我们引入一个例子:
食堂打饭,共有9份饭,窗口只有一个,但是有十个人需要打饭,每次服务窗口只能为一个顾客协作
这可怎么办,只能抢啊,第一个人抢到窗口前,打饭成功后,大喊一声:“你们可以打饭啦”
于是剩下的九个人又开始抢,再接着八个人,再接着七个人.......
当只剩下最后一个人只能叹息一声:“fuck!!!!!”
很抱歉拖了这么久才来完善这一篇博客
首先 我还是要就wait() notify() synchronized这三个关键字做一下基本的梳理,然后会给出一道例题的解答
在使用这三个关键字的时候显然我们是为了要实现线程之间的同步互斥访问
1. 我们需要临界资源的存在,线程要求同步的原因之一就是资源的独享,当我占有这个资源的时候,别的线程只能等我使用完才能执行,类比于食堂打饭这个操作,当我正在
打饭的时候后面的人必须等我,因为服务窗口只有一个位置,而这个位置就是临界资源
2. 我们需要一个同步信号量给其他的线程判断,当前是否拥有权限执行相关的操作,信号量标记着谁能访问当前的临界资源,当信号量没有指向自己的时候,需要放弃对临界资
源的把握,保证其他的线程能顺利访问资源并执行相关操作
2. 我们使用synchronize关键字来锁定临界资源,保证同一个时刻只有一个人能访问这个临界的资源
3. 而对于wait和notify 我们采用先等再叫的方式 也就是先考虑wait的情况, 当wait的情况不存在或者wait的事件已经发生的时候我们再去做执行操作,操作结束调用notify,唤
醒其他的线程,让它们有机会从wait事件中解脱,注意!!!!这里的wait和notify一般都是由synchronized的临界资源来调用
这里有一道例题,主线程执行十次后子线程执行二十次,像这样的循环,我们总共执行5次
很显然我们要让主线程做十次它的操作,然后通知子线程操作(注意这个时候主线程应该是进入了下一重的循环并且处于等待状态),子线程操作结束后重新唤醒主线程,让主线程继续它的十次操作,以此类推,循环5次便可以完成相应的操作
/**
*
* @author zero
* 1. Wait_NotifyTest.class is critical resource
Wait_NotifyTest.class是临界资源
* 2. isSubThread is signal
isSubThread是同步信号量
*/
/**
*
* @author zero
* 1. Wait_NotifyTest.class is critical resource
* 2. isSubThread is signal
*/
class Wait_NotifyTest extends Thread{
static Boolean isSubThread = false;
@Override
public void run() {
synchronized (Wait_NotifyTest.class) {
if(isSubThread) {
try {
Wait_NotifyTest.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=0; i<10; i++) {
System.out.println("Main Thread" + Thread.currentThread().getName() + "is runing....");
}
System.out.println("Main thread is over..... ");
isSubThread = true;
Wait_NotifyTest.class.notify();
}
}
class SubThread extends Thread {
@Override
public void run() {
synchronized (Wait_NotifyTest.class) {
if(!isSubThread) {
try {
Wait_NotifyTest.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=0; i<20; i++) {
System.out.println("SubThread " + Thread.currentThread().getName() + " is runing....");
}
System.out.println("SubThread is over...");
isSubThread = false;
Wait_NotifyTest.class.notify();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println("now the trun is " + i);
new Wait_NotifyTest().new SubThread().start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Wait_NotifyTest().start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
测试结果:
这里暂时先说到这里 因为今天还有些事情 晚点有时间的时候我会给出上面吃饭例子的代码实现