您的位置:首页 > 编程语言 > Java开发

[学习笔记]Java并发编程(详解wait(), notify(),sleep())

2016-04-16 13:17 561 查看
1.notify()

具体是怎么个意思呢?就是用来唤醒在此对象上等待的单个线程。说的有点太专业。打个比方,现在有十栋大房子,里面有很多被上了锁的房间,奇怪的是锁都是一样的,更不可思议的是,现在只有一把钥匙。而此时,张三用完钥匙后,就会发出归还钥匙的提醒,就相当于发出notify()通知,但是要注意的是,此时钥匙还在张三手中,只不过,当张三发出notify()通知后,JVM从那些整个沉睡的线程,唤醒一个。对应本例子,就是从其余的九栋大房子中唤醒一家,至于提醒谁来拿这把钥匙,就看JVM如何分配资源了。等到张三把钥匙归还后,那个被提醒的哪家,就可以使用该把钥匙来开房间门了。与此相对应的,还有一个notifyAll()方法。这是什么意思呢,还是本例,张三嗓门大,这时吼了一嗓子,即notifyAll(),所有沉睡的线程全都被吵醒了,当张三归还钥匙后,他们就可以竞争了,注意,刚才是JVM自动分配,而此时是线程之间竞争,比如优先级等等条件,是有区别的。

需要注意的是notify()方法执行后,并不是立即释放锁,而是等到加锁的代码块执行完后,才开始释放的,相当于本例中,张三只是发出了归还的通知,但是钥匙还没有归还,需要等到代码块,执行完后,才可以归还。

2.wait()

这个方法又是怎么个意思呢?当执行到这个方法时,就把钥匙归还,开始睡觉了。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

下面来看一个例子,加入我们要实现三个线程之间的同步操作,如何来实现呢?加入有三个线程分别用来输出A/B/C,如何能够三个线程之间顺序执行呢?这时候就需要采取线程之间同步的操作了,详见下面的代码。

[java] view plain copy print?

<span style="font-family:Comic Sans MS;font-size:18px;">package com.test;

public class MyThreadPrinter2 implements Runnable {

private String name;

private Object prev;

private Object self;

private MyThreadPrinter2(String name, Object prev, Object self) {

this.name = name; // A B C

this.prev = prev; // c a b

this.self = self; // a b c

}

@Override

public void run() {

int count = 10;

while (count > 0) {

// 加锁,锁的钥匙是prev

synchronized (prev) {

// 一把锁,锁的钥匙是self变量

synchronized (self) {

System.out.print(name);

count--;

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 唤醒另一个线程,但是也需要把本线程执行完后,才可以释放锁

self.notify(); //a b c

}

try {

// 释放对象锁,本线程进入休眠状态,等待被唤醒

prev.wait(); //睡觉觉了,等待被叫醒吧 // c a b

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public static void main(String[] args) throws Exception {

Object a = new Object();

Object b = new Object();

Object c = new Object();

MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);

MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);

MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);

new Thread(pa).start();

// 这样才可以保证按照顺序执行

Thread.sleep(10);

new Thread(pb).start();

Thread.sleep(10);

new Thread(pc).start();

Thread.sleep(10);

}

}</span>

下面来分析一下,首先通过线程之间的同步操作,上面的例子就会按照线程的顺序来分别执行,最终输出的结果就是ABCABCABC..............。

在此还是打一个比方,程序刚开始的时候,创建了三个线程的对象,也就是代表有三座大房子,下面开始执行了,第一个大房子里面有一个叫做张三的人员,打开了一个房子的钥匙c,然后拿着钥匙a,又一次打开了这个房子里面的一个箱子,最后完成后,把箱子的钥匙a给归还了,执行完后,张三开始在这个c钥匙的房子里面漫长的沉睡,也就是prev.wati()方法;当第二个人李四来到房子后,同样执行一边操作,此时需要注意的是,李四扔出的是箱子钥匙b,并在a钥匙的房间随着了;好吧懒货,王五来到了第三个大房子,同样执行了一遍操作,注意的是,王五扔出的是箱子钥匙c,在钥匙b房子睡着了。

重点来了,王五扔出箱子钥匙c后,此时就把在房子钥匙c中的张三给唤醒了,等到王五把钥匙归还后,此时张三又开始周而复始的运作了;于是大家可以按照逻辑接着向下分析一下。

在整个例子中需要注意一下几点

1.为了保证几个线程先能够顺序执行,于是加入了Thread.sleep(10)

2.每个对象执行wait()或者notify()方法时,只能在同一把锁的房子里面,例如

synchronized (self) {

System.out.print(name);

count--;

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

// 唤醒另一个线程,但是也需要把本线程执行完后,才可以释放锁

self.notify(); //a b c

}

房子的锁是self,所以执行self.notify()代表把我房子的钥匙给归还了。

有了上面的分析过程,下面我们出一道题,传统线程同步通信技术,子线程循环10次,接着主线程循环100次,又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次。这个例子又如何来实现呢?小编只在这里贴出源码,网上有很多解释的,可以按照小编的逻辑来分析一下。

[java] view plain copy print?

<span style="font-family:Comic Sans MS;font-size:18px;">package com.test;

public class TraditionalThreadCommunication {

/**

* @param args

*/

public static void main(String[] args) {

final Business business = new Business();

new Thread(

new Runnable() {

@Override

public void run() {

for(int i=1;i<=50;i++){

business.sub(i);

}

}

}

).start();

for(int i=1;i<=50;i++){

business.main(i);

}

}

}

class Business {

private boolean bShouldSub = true;

public synchronized void sub(int i){

while(!bShouldSub){

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

for(int j=1;j<=10;j++){

System.out.println("sub thread sequence of " + j + ",loop of " + i);

}

bShouldSub = false;

this.notify();

}

public synchronized void main(int i){

while(bShouldSub){

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

for(int j=1;j<=100;j++){

System.out.println("main thread sequence of " + j + ",loop of " + i);

}

bShouldSub = true;

this.notify();

}

}

</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: