51. }
运行结果:
这出现了安全问题,需加入同步,输入和输出都需要加,注意保证线程都用同一把锁进行同步
[java] view plaincopy
1. class Input implements Runnable{
2. private Res r;
3. Input(Res r){
4. this.r = r;
5. }
6. public void run(){
7. int flag = 0;
8. while(true){
9. synchronized(r){
10. if(flag==0){
11. r.name = "张三";
12. r.sex = "男";
13. }else{
14. r.name = "李四";
15. r.sex = "女";
16. }
17. }
18. flag = (flag+1)%2;//交替打印
19. }
20. }
21. }
22.
23. class Output implements Runnable{
24. private Res r;
25. Output(Res r){
26. this.r = r;
27. }
28. public void run(){
29. while(true){
30. synchronized(r){
31. System.out.println(r.name+"..."+r.sex);
32. }
33. }
34. }
35. }
等待唤醒机制
多个线程操作共享数据时,保证数据交替被线程操作(比如输入一个数据,就输出一个数据的情况),则使用等待唤醒机制
wait();//该方法让线程进入线程池等待
notify();//该方法唤醒线程池中第一个等待的共有同一把锁的线程,该机制会导致出现生产者消费者问题(多个生产者和消费者的时候)
notifyAll();//该方法唤醒所有共有同一把锁的等待线程
都使用在同步代码中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中?
因为这些方法在操作同步中的线程时,都必须要标示他们所操作线程持有的锁,只有同一个锁上的被等待线程可以被同一个notify唤醒,不可以对不同锁中的线程进行唤醒。也就是说等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。
关键代码:
[java] view plaincopy
1. class Res
2. {
3. String name;
4. String sex;
5. boolean flag = false;//设置标记,判断资源状态,默认为假,表示资源为空。
6. }
7.
8. class Input implements Runnable
9. {
10. private Res r ;
11. Input(Res r)
12. {
13. this.r = r;
14. }
15. public void run()
16. {
17. int x = 0;
18. while(true)
19. {
20. synchronized(r)
21. {
22.
23. if(r.flag)
24. try{r.wait();}catch(Exception e){}//如果flag为真,表示资源存在,则使输入线程等待,r.wait()表示等待持有r这个锁的线程
25. if(x==0)
26. {
27. r.name="张三";
28. r.sex="男";
29. }
30. else
31. {
32. r.name="李四";
33. r.sex = "女";
34. }
35. x = (x+1)%2;
36. r.flag = true;//改变资源状态的标记
37. r.notify();//唤醒共用该锁的第一个其他线程
38. }
39. }
40. }
41. }
42.
43. class Output implements Runnable
44. {
45. private Res r ;
46.
47. Output(Res r)
48. {
49. this.r = r;
50. }
51. public void run()
52. {
53. while(true)
54. {
55. synchronized(r)
56. {
57. if(!r.flag)
58. try{r.wait();}catch(Exception e){}
59. System.out.println(r.name+"...."+r.sex);
60. r.flag = false;
61. r.notify();
62. }
63. }
64. }
65. }
66.
67. class InputOutputDemo
68. {
69. public static void main(String[] args)
70. {
71. Res r = new Res();
72.
73. Input in = new Input(r);
74. Output out = new Output(r);
75.
76. Thread t1 = new Thread(in);
77. Thread t2 = new Thread(out);
78.
79. t1.start();
80. t2.start();
81. }
82. }
或者将代码优化为(使用同步函数)
[java] view plaincopy
1. class Res
2. {
3. private String name;
4. private String sex;
5. private boolean flag = false;
6.
7. public synchronized void set(String name,String sex)
8. {
9. if(flag)
10. try{this.wait();}catch(Exception e){}
11. this.name = name;
12.
13. this.sex = sex;
14. flag = true;
15. this.notify();
16. }
17. public synchronized void out()
18. {
19. if(!flag)
20. try{this.wait();}catch(Exception e){}
21. System.out.println(name+"........"+sex);
22. flag = false;
23. this.notify();
24. }
25. }
26.
27. class Input implements Runnable
28. {
29. private Res r ;
30. Input(Res r)
31. {
32. this.r = r;
33. }
34. public void run()
35. {
36. int x = 0;
37. while(true)
38. {
39. if(x==0)
40. r.set("张三","男");
41. else
42. r.set("李四","女");
43. x = (x+1)%2;
44. }
45. }
46. }
47.
48. class Output implements Runnable
49. {
50. private Res r ;
51.
52. Output(Res r)
53. {
54. this.r = r;
55. }
56. public void run()
57. {
58. while(true)
59. {
60. r.out();
61. }
62. }
63. }
64.
65. class InputOutputDemo2
66. {
67. public static void main(String[] args)
68. {
69. Res r = new Res();
70.
71. new Thread(new Input(r)).start();
72. new Thread(new Output(r)).start();
73. }
74. }
|
|