- 浏览: 69405 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
wan_jm:
超时是服务端的问题, 客户端不管的。所以一楼所说的情况算ses ...
关于ajax应用中session过期问题的几个解决方案 -
wulinshishen:
嗯!值得去学下
用struts向数据库中储存图片 -
proje:
值得学习,谢谢了哦
用struts向数据库中储存图片 -
Quen:
好好学习一下
用AJAX来控制书签和回退按钮 -
superliu8:
先下来看看
自学的下载看看
Java监视器支持两种线程:互斥和协作。
前面我们介绍了采用对象锁和重入锁来实现的互斥。这一篇中,我们来看一看线程的协作。
举个例子:有一家汉堡店举办吃汉堡比赛,决赛时有3个顾客来吃,3个厨师来做,一个服务员负责协调汉堡的数量。为了避免浪费,制作好的汉堡被放进一个能装有10个汉堡的长条状容器中,按照先进先出的原则取汉堡。如果容器被装满,则厨师停止做汉堡,如果顾客发现容器内的汉堡吃完了,就可以拍响容器上的闹铃,提醒厨师再做几个汉堡出来。此时服务员过来安抚顾客,让他等待。而一旦厨师的汉堡做出来,就会让服务员通知顾客,汉堡做好了,让顾客继续过来取汉堡。
这里,顾客其实就是我们所说的消费者,而厨师就是生产者。容器是决定厨师行为的监视器,而服务员则负责监视顾客的行为。
在JVM中,此种监视器被称为等待并唤醒监视器。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
在这种监视器中,一个已经持有该监视器的线程,可以通过调用监视对象的wait方法,暂停自身的执行,并释放监视器,自己进入一个等待区,直到监视器内的其他线程调用了监视对象的notify方法。当一个线程调用唤醒命令以后,它会持续持有监视器,直到它主动释放监视器。而这之后,等待线程会苏醒,其中的一个会重新获得监视器,判断条件状态,以便决定是否继续进入等待状态或者执行监视区域,或者退出。
请看下面的代码:
1. public class NotifyTest {
2. private String flag = "true";
3.
4. class NotifyThread extends Thread{
5. public NotifyThread(String name) {
6. super(name);
7. }
8. public void run() {
9. try {
10. sleep(3000);//推迟3秒钟通知
11. } catch (InterruptedException e) {
12. e.printStackTrace();
13. }
14.
15. flag = "false";
16. flag.notify();
17. }
18. };
19.
20. class WaitThread extends Thread {
21. public WaitThread(String name) {
22. super(name);
23. }
24.
25. public void run() {
26.
27. while (flag!="false") {
28. System.out.println(getName() + " begin waiting!");
29. long waitTime = System.currentTimeMillis();
30. try {
31. flag.wait();
32. } catch (InterruptedException e) {
33. e.printStackTrace();
34. }
35. waitTime = System.currentTimeMillis() - waitTime;
36. System.out.println("wait time :"+waitTime);
37. }
38. System.out.println(getName() + " end waiting!");
39.
40. }
41. }
42.
43. public static void main(String[] args) throws InterruptedException {
44. System.out.println("Main Thread Run!");
45. NotifyTest test = new NotifyTest();
46. NotifyThread notifyThread =test.new NotifyThread("notify01");
47. WaitThread waitThread01 = test.new WaitThread("waiter01");
48. WaitThread waitThread02 = test.new WaitThread("waiter02");
49. WaitThread waitThread03 = test.new WaitThread("waiter03");
50. notifyThread.start();
51. waitThread01.start();
52. waitThread02.start();
53. waitThread03.start();
54. }
55.
56. }
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
这段代码启动了三个简单的wait线程,当他们处于等待状态以后,试图由一个notify线程来唤醒。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
运行这段程序,你会发现,满屏的java.lang.IllegalMonitorStateException,根本不是你想要的结果。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
请注意以下几个事实:
1. 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
2. 无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)。
3. 如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
4. JVM基于多线程,默认情况下不能保证运行时线程的时序性。
也就是说,当线程在调用某个对象的wait或者notify方法的时候,要先取得该对象的控制权,换句话说,就是进入这个对象的监视器。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
通过前面对同步的讨论,我们知道,要让一个线程进入某个对象的监视器,通常有三种方法:
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
1: 执行对象的某个同步实例方法
2: 执行对象对应的同步静态方法
3: 执行对该对象加同步锁的同步块
显然,在上面的例程中,我们用第三种方法比较合适。
于是我们将上面的wait和notify方法调用包在同步块中。
1. synchronized (flag) {
2. flag = "false";
3. flag.notify();
4. }
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
1. synchronized (flag) {
2. while (flag!="false") {
3. System.out.println(getName() + " begin waiting!");
4. long waitTime = System.currentTimeMillis();
5. try {
6. flag.wait();
7. } catch (InterruptedException e) {
8. e.printStackTrace();
9. }
10. waitTime = System.currentTimeMillis() - waitTime;
11. System.out.println("wait time :"+waitTime);
12. }
13. System.out.println(getName() + " end waiting!");
14. }
但是,运行这个程序,我们发现事与愿违。那个非法监视器异常又出现了。。。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
我们注意到,针对flag的同步块中,我们实际上已经更改了flag对对象的引用: flag="false";
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
显然,这样一来,同步块也无能为力了,因为我们根本不是针对唯一的一个对象在进行同步。
我们不妨将flag封装到JavaBean或者数组中去,这样用JavaBean对象或者数组对象进行同步,就可以达到既能修改里面参数又不耽误同步的目的。
1. private String flag[] = {"true"};
1. synchronized (flag) {
2. flag[0] = "false";
3. flag.notify();
4. }
1. synchronized (flag) {
2. flag[0] = "false";
3. flag.notify();
4. }synchronized (flag) {
5. while (flag[0]!="false") {
6. System.out.println(getName() + " begin waiting!");
7. long waitTime = System.currentTimeMillis();
8. try {
9. flag.wait();
10.
11. } catch (InterruptedException e) {
12. e.printStackTrace();
13. }
运行这个程序,看不到异常了。但是仔细观察结果,貌似只有一个线程被唤醒。利用jconsole等工具查看线程状态,发现的确还是有两个线程被阻塞的。这是为啥呢?
程序中使用了flag.notify()方法。只能是随机的唤醒一个线程。我们可以改用flag.notifyAll()方法。这样,所有被阻塞的线程都会被唤醒了。
最终代码请读者自己修改,这里不再赘述。
好了,亲爱的读者们,让我们回到开篇提到的汉堡店大赛问题当中去,来看一看厨师、服务生和顾客是怎么协作进行这个比赛的。
首先我们构造故事中的三个次要对象:汉堡包、存放汉堡包的容器、服务生
public class Waiter {//服务生,这是个配角,不需要属性。
}
class Hamberg {
//汉堡包
private int id;//汉堡编号
private String cookerid;//厨师编号
public Hamberg(int id, String cookerid){
this.id = id;
this.cookerid = cookerid;
System.out.println(this.toString()+"was made!");
}
@Override
public String toString() {
return "#"+id+" by "+cookerid;
}
}
class HambergFifo {
//汉堡包容器
List<Hamberg> hambergs = new ArrayList<Hamberg>();//借助ArrayList来存放汉堡包
int maxSize = 10;//指定容器容量
//放入汉堡
public <T extends Hamberg> void push(T t) {
hambergs.add(t);
}
//取出汉堡
public Hamberg pop() {
Hamberg h = hambergs.get(0);
hambergs.remove(0);
return h;
}
//判断容器是否为空
public boolean isEmpty() {
return hambergs.isEmpty();
}
//判断容器内汉堡的个数
public int size() {
return hambergs.size();
}
//返回容器的最大容量
public int getMaxSize() {
return this.maxSize;
}
}
接下来我们构造厨师对象:
class Cooker implements Runnable {
//厨师要面对容器
HambergFifo pool;
//还要面对服务生
Waiter waiter;
public Cooker(Waiter waiter, HambergFifo hambergStack) {
this.pool = hambergStack;
this.waiter = waiter;
}
//制造汉堡
public void makeHamberg() {
//制造的个数
int madeCount = 0;
//因为容器满,被迫等待的次数
int fullFiredCount = 0;
try {
while (true) {
//制作汉堡前的准备工作
Thread.sleep(1000);
if (pool.size() < pool.getMaxSize()) {
synchronized (waiter) {
//容器未满,制作汉堡,并放入容器。
pool.push(new Hamberg(++madeCount,Thread.currentThread().getName()));
//说出容器内汉堡数量
System.out.println(Thread.currentThread().getName() + ": There are "
+ pool.size() + " Hambergs in all");
//让服务生通知顾客,有汉堡可以吃了
waiter.notifyAll();
System.out.println("### Cooker: waiter.notifyAll() :"+
" Hi! Customers, we got some new Hambergs!");
}
} else {
synchronized (pool) {
if (fullFiredCount++ < 10) {
//发现容器满了,停止做汉堡的尝试。
System.out.println(Thread.currentThread().getName() +
": Hamberg Pool is Full, Stop making hamberg");
System.out.println("### Cooker: pool.wait()");
//汉堡容器的状况使厨师等待
pool.wait();
} else {
return;
}
}
}
//做完汉堡要进行收尾工作,为下一次的制作做准备。
Thread.sleep(1000);
}
} catch (Exception e) {
madeCount--;
e.printStackTrace();
}
}
public void run() {
makeHamberg();
}
}
接下来,我们构造顾客对象:
class Customer implements Runnable {
//顾客要面对服务生
Waiter waiter;
//也要面对汉堡包容器
HambergFifo pool;
//想要记下自己吃了多少汉堡
int ateCount = 0;
//吃每个汉堡的时间不尽相同
long sleeptime;
//用于产生随机数
Random r = new Random();
public Customer(Waiter waiter, HambergFifo pool) {
this.waiter = waiter;
this.pool = pool;
}
public void run() {
while (true) {
try {
//取汉堡
getHamberg();
//吃汉堡
eatHamberg();
} catch (Exception e) {
synchronized (waiter) {
System.out.println(e.getMessage());
//若取不到汉堡,要和服务生打交道
try {
System.out.println("### Customer: waiter.wait():"+
" Sorry, Sir, there is no hambergs left, please wait!");
System.out.println(Thread.currentThread().getName()
+ ": OK, Waiting for new hambergs");
//服务生安抚顾客,让他等待。
waiter.wait();
continue;
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
private void eatHamberg() {
try {
//吃每个汉堡的时间不等
sleeptime = Math.abs(r.nextInt(3000)) * 5;
System.out.println(Thread.currentThread().getName()
+ ": I'm eating the hamberg for " + sleeptime + " milliseconds");
Thread.sleep(sleeptime);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getHamberg() throws Exception {
Hamberg hamberg = null;
synchronized (pool) {
try {
//在容器内取汉堡
hamberg = pool.pop();
ateCount++;
System.out.println(Thread.currentThread().getName()
+ ": I Got " + ateCount + " Hamberg " + hamberg);
System.out.println(Thread.currentThread().getName()
+ ": There are still " + pool.size() + " hambergs left");
} catch (Exception e) {
pool.notifyAll();
System.out.println("### Customer: pool.notifyAll()");
throw new Exception(Thread.currentThread().getName() +
": OH MY GOD!!!! No hambergs left, Waiter![Ring the bell besides the hamberg pool]");
}
}
}
}
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
最后,我们构造汉堡店,让这个故事发生:
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
public class HambergShop {
Waiter waiter = new Waiter();
HambergFifo hambergPool = new HambergFifo();
Customer c1 = new Customer(waiter, hambergPool);
Customer c2 = new Customer(waiter, hambergPool);
Customer c3 = new Customer(waiter, hambergPool);
Cooker cooker = new Cooker(waiter, hambergPool);
public static void main(String[] args) {
HambergShop hambergShop = new HambergShop();
Thread t1 = new Thread(hambergShop.c1, "Customer 1");
Thread t2 = new Thread(hambergShop.c2, "Customer 2");
Thread t3 = new Thread(hambergShop.c3, "Customer 3");
Thread t4 = new Thread(hambergShop.cooker, "Cooker 1");
Thread t5 = new Thread(hambergShop.cooker, "Cooker 2");
Thread t6 = new Thread(hambergShop.cooker, "Cooker 3");
t4.start();
t5.start();
t6.start();
try {
Thread.sleep(10000);
} catch (Exception e) {
}
t1.start();
t2.start();
t3.start();
}
}
运行这个程序吧,然后你会看到我们汉堡店的比赛进行的很好,只是不
知道那些顾客是不是会被撑到。。。
前面我们介绍了采用对象锁和重入锁来实现的互斥。这一篇中,我们来看一看线程的协作。
举个例子:有一家汉堡店举办吃汉堡比赛,决赛时有3个顾客来吃,3个厨师来做,一个服务员负责协调汉堡的数量。为了避免浪费,制作好的汉堡被放进一个能装有10个汉堡的长条状容器中,按照先进先出的原则取汉堡。如果容器被装满,则厨师停止做汉堡,如果顾客发现容器内的汉堡吃完了,就可以拍响容器上的闹铃,提醒厨师再做几个汉堡出来。此时服务员过来安抚顾客,让他等待。而一旦厨师的汉堡做出来,就会让服务员通知顾客,汉堡做好了,让顾客继续过来取汉堡。
这里,顾客其实就是我们所说的消费者,而厨师就是生产者。容器是决定厨师行为的监视器,而服务员则负责监视顾客的行为。
在JVM中,此种监视器被称为等待并唤醒监视器。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
在这种监视器中,一个已经持有该监视器的线程,可以通过调用监视对象的wait方法,暂停自身的执行,并释放监视器,自己进入一个等待区,直到监视器内的其他线程调用了监视对象的notify方法。当一个线程调用唤醒命令以后,它会持续持有监视器,直到它主动释放监视器。而这之后,等待线程会苏醒,其中的一个会重新获得监视器,判断条件状态,以便决定是否继续进入等待状态或者执行监视区域,或者退出。
请看下面的代码:
1. public class NotifyTest {
2. private String flag = "true";
3.
4. class NotifyThread extends Thread{
5. public NotifyThread(String name) {
6. super(name);
7. }
8. public void run() {
9. try {
10. sleep(3000);//推迟3秒钟通知
11. } catch (InterruptedException e) {
12. e.printStackTrace();
13. }
14.
15. flag = "false";
16. flag.notify();
17. }
18. };
19.
20. class WaitThread extends Thread {
21. public WaitThread(String name) {
22. super(name);
23. }
24.
25. public void run() {
26.
27. while (flag!="false") {
28. System.out.println(getName() + " begin waiting!");
29. long waitTime = System.currentTimeMillis();
30. try {
31. flag.wait();
32. } catch (InterruptedException e) {
33. e.printStackTrace();
34. }
35. waitTime = System.currentTimeMillis() - waitTime;
36. System.out.println("wait time :"+waitTime);
37. }
38. System.out.println(getName() + " end waiting!");
39.
40. }
41. }
42.
43. public static void main(String[] args) throws InterruptedException {
44. System.out.println("Main Thread Run!");
45. NotifyTest test = new NotifyTest();
46. NotifyThread notifyThread =test.new NotifyThread("notify01");
47. WaitThread waitThread01 = test.new WaitThread("waiter01");
48. WaitThread waitThread02 = test.new WaitThread("waiter02");
49. WaitThread waitThread03 = test.new WaitThread("waiter03");
50. notifyThread.start();
51. waitThread01.start();
52. waitThread02.start();
53. waitThread03.start();
54. }
55.
56. }
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
这段代码启动了三个简单的wait线程,当他们处于等待状态以后,试图由一个notify线程来唤醒。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
运行这段程序,你会发现,满屏的java.lang.IllegalMonitorStateException,根本不是你想要的结果。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
请注意以下几个事实:
1. 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
2. 无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)。
3. 如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
4. JVM基于多线程,默认情况下不能保证运行时线程的时序性。
也就是说,当线程在调用某个对象的wait或者notify方法的时候,要先取得该对象的控制权,换句话说,就是进入这个对象的监视器。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
通过前面对同步的讨论,我们知道,要让一个线程进入某个对象的监视器,通常有三种方法:
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
1: 执行对象的某个同步实例方法
2: 执行对象对应的同步静态方法
3: 执行对该对象加同步锁的同步块
显然,在上面的例程中,我们用第三种方法比较合适。
于是我们将上面的wait和notify方法调用包在同步块中。
1. synchronized (flag) {
2. flag = "false";
3. flag.notify();
4. }
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
1. synchronized (flag) {
2. while (flag!="false") {
3. System.out.println(getName() + " begin waiting!");
4. long waitTime = System.currentTimeMillis();
5. try {
6. flag.wait();
7. } catch (InterruptedException e) {
8. e.printStackTrace();
9. }
10. waitTime = System.currentTimeMillis() - waitTime;
11. System.out.println("wait time :"+waitTime);
12. }
13. System.out.println(getName() + " end waiting!");
14. }
但是,运行这个程序,我们发现事与愿违。那个非法监视器异常又出现了。。。
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
我们注意到,针对flag的同步块中,我们实际上已经更改了flag对对象的引用: flag="false";
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
显然,这样一来,同步块也无能为力了,因为我们根本不是针对唯一的一个对象在进行同步。
我们不妨将flag封装到JavaBean或者数组中去,这样用JavaBean对象或者数组对象进行同步,就可以达到既能修改里面参数又不耽误同步的目的。
1. private String flag[] = {"true"};
1. synchronized (flag) {
2. flag[0] = "false";
3. flag.notify();
4. }
1. synchronized (flag) {
2. flag[0] = "false";
3. flag.notify();
4. }synchronized (flag) {
5. while (flag[0]!="false") {
6. System.out.println(getName() + " begin waiting!");
7. long waitTime = System.currentTimeMillis();
8. try {
9. flag.wait();
10.
11. } catch (InterruptedException e) {
12. e.printStackTrace();
13. }
运行这个程序,看不到异常了。但是仔细观察结果,貌似只有一个线程被唤醒。利用jconsole等工具查看线程状态,发现的确还是有两个线程被阻塞的。这是为啥呢?
程序中使用了flag.notify()方法。只能是随机的唤醒一个线程。我们可以改用flag.notifyAll()方法。这样,所有被阻塞的线程都会被唤醒了。
最终代码请读者自己修改,这里不再赘述。
好了,亲爱的读者们,让我们回到开篇提到的汉堡店大赛问题当中去,来看一看厨师、服务生和顾客是怎么协作进行这个比赛的。
首先我们构造故事中的三个次要对象:汉堡包、存放汉堡包的容器、服务生
public class Waiter {//服务生,这是个配角,不需要属性。
}
class Hamberg {
//汉堡包
private int id;//汉堡编号
private String cookerid;//厨师编号
public Hamberg(int id, String cookerid){
this.id = id;
this.cookerid = cookerid;
System.out.println(this.toString()+"was made!");
}
@Override
public String toString() {
return "#"+id+" by "+cookerid;
}
}
class HambergFifo {
//汉堡包容器
List<Hamberg> hambergs = new ArrayList<Hamberg>();//借助ArrayList来存放汉堡包
int maxSize = 10;//指定容器容量
//放入汉堡
public <T extends Hamberg> void push(T t) {
hambergs.add(t);
}
//取出汉堡
public Hamberg pop() {
Hamberg h = hambergs.get(0);
hambergs.remove(0);
return h;
}
//判断容器是否为空
public boolean isEmpty() {
return hambergs.isEmpty();
}
//判断容器内汉堡的个数
public int size() {
return hambergs.size();
}
//返回容器的最大容量
public int getMaxSize() {
return this.maxSize;
}
}
接下来我们构造厨师对象:
class Cooker implements Runnable {
//厨师要面对容器
HambergFifo pool;
//还要面对服务生
Waiter waiter;
public Cooker(Waiter waiter, HambergFifo hambergStack) {
this.pool = hambergStack;
this.waiter = waiter;
}
//制造汉堡
public void makeHamberg() {
//制造的个数
int madeCount = 0;
//因为容器满,被迫等待的次数
int fullFiredCount = 0;
try {
while (true) {
//制作汉堡前的准备工作
Thread.sleep(1000);
if (pool.size() < pool.getMaxSize()) {
synchronized (waiter) {
//容器未满,制作汉堡,并放入容器。
pool.push(new Hamberg(++madeCount,Thread.currentThread().getName()));
//说出容器内汉堡数量
System.out.println(Thread.currentThread().getName() + ": There are "
+ pool.size() + " Hambergs in all");
//让服务生通知顾客,有汉堡可以吃了
waiter.notifyAll();
System.out.println("### Cooker: waiter.notifyAll() :"+
" Hi! Customers, we got some new Hambergs!");
}
} else {
synchronized (pool) {
if (fullFiredCount++ < 10) {
//发现容器满了,停止做汉堡的尝试。
System.out.println(Thread.currentThread().getName() +
": Hamberg Pool is Full, Stop making hamberg");
System.out.println("### Cooker: pool.wait()");
//汉堡容器的状况使厨师等待
pool.wait();
} else {
return;
}
}
}
//做完汉堡要进行收尾工作,为下一次的制作做准备。
Thread.sleep(1000);
}
} catch (Exception e) {
madeCount--;
e.printStackTrace();
}
}
public void run() {
makeHamberg();
}
}
接下来,我们构造顾客对象:
class Customer implements Runnable {
//顾客要面对服务生
Waiter waiter;
//也要面对汉堡包容器
HambergFifo pool;
//想要记下自己吃了多少汉堡
int ateCount = 0;
//吃每个汉堡的时间不尽相同
long sleeptime;
//用于产生随机数
Random r = new Random();
public Customer(Waiter waiter, HambergFifo pool) {
this.waiter = waiter;
this.pool = pool;
}
public void run() {
while (true) {
try {
//取汉堡
getHamberg();
//吃汉堡
eatHamberg();
} catch (Exception e) {
synchronized (waiter) {
System.out.println(e.getMessage());
//若取不到汉堡,要和服务生打交道
try {
System.out.println("### Customer: waiter.wait():"+
" Sorry, Sir, there is no hambergs left, please wait!");
System.out.println(Thread.currentThread().getName()
+ ": OK, Waiting for new hambergs");
//服务生安抚顾客,让他等待。
waiter.wait();
continue;
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
private void eatHamberg() {
try {
//吃每个汉堡的时间不等
sleeptime = Math.abs(r.nextInt(3000)) * 5;
System.out.println(Thread.currentThread().getName()
+ ": I'm eating the hamberg for " + sleeptime + " milliseconds");
Thread.sleep(sleeptime);
} catch (Exception e) {
e.printStackTrace();
}
}
private void getHamberg() throws Exception {
Hamberg hamberg = null;
synchronized (pool) {
try {
//在容器内取汉堡
hamberg = pool.pop();
ateCount++;
System.out.println(Thread.currentThread().getName()
+ ": I Got " + ateCount + " Hamberg " + hamberg);
System.out.println(Thread.currentThread().getName()
+ ": There are still " + pool.size() + " hambergs left");
} catch (Exception e) {
pool.notifyAll();
System.out.println("### Customer: pool.notifyAll()");
throw new Exception(Thread.currentThread().getName() +
": OH MY GOD!!!! No hambergs left, Waiter![Ring the bell besides the hamberg pool]");
}
}
}
}
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
最后,我们构造汉堡店,让这个故事发生:
转载注明出处:http://x- spirit.iteye.com/、http: //www.blogjava.net/zhangwei217245/
public class HambergShop {
Waiter waiter = new Waiter();
HambergFifo hambergPool = new HambergFifo();
Customer c1 = new Customer(waiter, hambergPool);
Customer c2 = new Customer(waiter, hambergPool);
Customer c3 = new Customer(waiter, hambergPool);
Cooker cooker = new Cooker(waiter, hambergPool);
public static void main(String[] args) {
HambergShop hambergShop = new HambergShop();
Thread t1 = new Thread(hambergShop.c1, "Customer 1");
Thread t2 = new Thread(hambergShop.c2, "Customer 2");
Thread t3 = new Thread(hambergShop.c3, "Customer 3");
Thread t4 = new Thread(hambergShop.cooker, "Cooker 1");
Thread t5 = new Thread(hambergShop.cooker, "Cooker 2");
Thread t6 = new Thread(hambergShop.cooker, "Cooker 3");
t4.start();
t5.start();
t6.start();
try {
Thread.sleep(10000);
} catch (Exception e) {
}
t1.start();
t2.start();
t3.start();
}
}
运行这个程序吧,然后你会看到我们汉堡店的比赛进行的很好,只是不
知道那些顾客是不是会被撑到。。。
发表评论
-
java.security.NoSuchAlgorithmException: DH KeyPairGenerator not available 异常处理
2012-07-18 10:17 7448在Linux搭建SFTP文件上传时,在本机测试可以,但在服务器 ... -
Struts 、 Spring 、 Hibernate 在SSH中各层的作用
2010-05-20 09:42 0简单的说: Struts 控制用的 Hibernate 操作数 ... -
Java 获取系统信息及Desktop类
2010-03-30 15:38 2032原来在GUI界面的MailClient中加入了类似OutLoo ... -
用代码来测试JAVA中数据类型的存储大小
2010-03-30 15:28 1193感谢CSDN jack_chen import java. ... -
收集整理: JavaScript格式化和解析日期, JSTL格式化和解析日期
2010-03-30 11:47 1046JSP开发时, 在页面中格式化和解析日期始终是个头疼的事情. ... -
Java 多线程同步问题的探究(三、Lock来了,大家都让开【1. 认识重入锁】)
2010-03-30 11:38 731我想很多购买了《Java程序员面试宝典》之类图书的朋友一定对下 ... -
通JMX连接glassfish服务器
2010-03-30 11:36 1233HashMap env = new HashMap(1); ... -
spring中注入方式有多中,如构造方法,SET/GET方法等.lookup方法注入有些与其它的不一样,此方法注入常用来得到一个非单例对象.
2010-03-30 10:00 1507ervlet/JSP技术和ASP、PHP等相比,由于其多线程运 ... -
关于ajax应用中session过期问题的几个解决方案
2010-03-30 09:58 3026现在web开发中,ajax应用的比较多。关于此方面的框架也不少 ... -
用Struts的Token机制解决表单重复提交
2010-03-30 09:55 674Struts的Token(令牌)机 ...
相关推荐
g: 利用互斥量来解决线程同步互斥问题 h: problem1 生产者消费者问题 (1生产者 1消费者 1缓冲区) problem1 more 生产者消费者问题 (1生产者 2消费者 4缓冲区) problem2 读者与写着问题 I: 信号量 semaphore ...
本代码是用JAVA实现的生产者与消费者的问题,线程间的同步与互斥功能
操作系统实验 多线程同步与互斥 java编写 可动态创建
解决多线程编程中的同步互斥问题
java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料
用java实现多线程并发中的读者与写者问题,能够实现多线程对临界资源的同步有序访问。 具体实现为: 给定一个队列A[1-10][1-100000]、元素编号1-10,其中每个元素包含10万个随机数。创建若干个线程,各循环100次;...
wait set——线程的休息室 wait方法——把线程放入wait set notify方法——从wait set拿出线程 notifyAll方法——从wait set拿出所有线程 wait、notify、notifyAll是Object类的方法 线程的状态移转 跟线程有关的其他...
Java多线程同步具体实例讲解 .doc
(1) 通过编写程序实现进程同步和互斥,掌握有关进程(线程)同步与互斥的原理,以及解决进程(线程)同步和互斥的算法,从而进一步巩固进程(线程)同步和互斥等有关的内容。 (2) 了解Windows2000/XP中多线程的...
在linux上分别用多进程和多线程实现的同步互斥操作(源代码)
通过JAVA多线程同步和互斥的技术实现CSMA/CD协议的模拟
C#的多线程同步,C#中四种进程或线程同步互斥的控制方法
java多线程小程序实例 java多线程小程序实例
本例将模仿经典的线程同步互斥例子——生产者和消费者问题,来演示 java 强大的多线程机制。生产者和消费者共享一个数据,当数据为0 时,消费者不可访问,生产者可访问数据,每次访问数据加1;当数据到达100 时,...
java ATM存取一体机(线程同步互斥) java ATM存取一体机(线程同步互斥)
在《秒杀多线程系列》的前十五篇中介绍多线程的相关概念,多线程同步互斥问题《秒杀多线程第四篇一个经典的多线程同步问题》及解决多线程同步互斥的常用方法——关键段、事件、互斥量、信号量、读写锁。为了让大家...
Linux下多线程及多进程及同步与互斥编程详细介绍
windows多线程的同步和互斥
C#.NET多线程实例6个(包括多线程基本使用,多线程互斥等全部多线程使用实例)