Java多线程(二)

来源:互联网 发布:与程序员算法有关的书 编辑:程序博客网 时间:2024/05/16 07:55

------android培训java培训、java学习型技术博客、期待与您交流!------------


七、线程间通信

        其实就是多个线程在操作同一个资源,但是操作的动作不同。

1、使用同步操作同一资源的示例:

[java] view plaincopy

1. /* 

2.     有一个资源 

3. 一个线程往里存东西,如果里边没有的话 

4. 一个线程往里取东西,如果里面有得话 

5. */  

6.   

7. //资源  

8. class Resource  

9. {  

10.     private String name;  

11.     private String sex;  

12.     private boolean flag=false;  

13.       

14.     public synchronized void setInput(String name,String sex)  

15.     {  

16.         if(flag)  

17.         {  

18.             try{wait();}catch(Exception e){}//如果有资源时,等待资源取出  

19.         }  

20.         this.name=name;  

21.         this.sex=sex;  

22.   

23.         flag=true;//表示有资源  

24.         notify();//唤醒等待  

25.     }  

26.   

27.     public synchronized void getOutput()  

28.     {         

29.         if(!flag)  

30.         {  

31.             try{wait();}catch(Exception e){}//如果木有资源,等待存入资源  

32.         }  

33.         System.out.println("name="+name+"---sex="+sex);//这里用打印表示取出  

34.                   

35.         flag=false;//资源已取出  

36.         notify();//唤醒等待  

37.     }  

38. }  

39.   

40.   

41. //存线程  

42. class Input implements Runnable  

43. {  

44.     private Resource r;  

45.     Input(Resource r)  

46.     {  

47.         this.r=r;  

48.     }  

49.     public void run()//复写run方法  

50.     {  

51.         int x=0;  

52.         while(true)  

53.         {  

54.             if(x==0)//交替打印张三和王羲之  

55.             {  

56.                 r.setInput("张三",".....man");  

57.             }  

58.             else  

59.             {  

60.                 r.setInput("王羲之","..woman");  

61.             }  

62.             x=(x+1)%2;//控制交替打印  

63.         }  

64.     }  

65. }  

66.   

67. //取线程  

68. class Output implements Runnable  

69. {  

70.     private Resource r;  

71.     Output(Resource r)  

72.     {  

73.         this.r=r;  

74.     }  

75.     public void run()//复写run方法  

76.     {  

77.         while(true)  

78.         {  

79.             r.getOutput();  

80.         }  

81.     }  

82. }  

83.   

84.   

85.   

86. class ResourceDemo2   

87. {  

88.     public static void main(String[] args)   

89.     {  

90.         Resource r = new Resource();//表示操作的是同一个资源  

91.   

92.         new Thread(new Input(r)).start();//开启存线程  

93.   

94.         new Thread(new Output(r)).start();//开启取线程  

95.     }  

96. }  

结果:部分截图


 几个小问题:

        1wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?

                a,这些方法存在与同步中。

                b,使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。

                c,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

        2wait(),sleep()有什么区别?

              wait():释放cpu执行权,释放锁。

              sleep():释放cpu执行权,不释放锁。

        3为甚么要定义notifyAll?

        因为在需要唤醒对方线程时。如果只用notify,容易出现只唤醒本方线程的情况。导致程序中的所以线程都等待。

2、JDK1.5中提供了多线程升级解决方案。

        将同步synchronized替换成显示的Lock操作。将Object中wait,notify,notifyAll,替换成了Condition对象。该Condition对象可以通过Lock锁进行获取,并支持多个相关的Condition对象。

升级解决方案的示例:

[java] view plaincopy

1. /* 

2. 生产者生产商品,供消费者使用 

3. 有两个或者多个生产者,生产一次就等待消费一次 

4. 有两个或者多个消费者,等待生产者生产一次就消费掉 

5.  

6. */  

7.   

8. import java.util.concurrent.locks.*;  

9.   

10. class Resource   

11. {     

12.     private String name;  

13.     private int count=1;  

14.     private boolean flag = false;  

15.       

16.     //多态  

17.     private Lock lock=new ReentrantLock();  

18.   

19.     //创建两Condition对象,分别来控制等待或唤醒本方和对方线程  

20.     Condition condition_pro=lock.newCondition();  

21.     Condition condition_con=lock.newCondition();  

22.   

23.     //p1、p2共享此方法  

24.     public void setProducer(String name)throws InterruptedException  

25.     {  

26.         lock.lock();//锁  

27.         try  

28.         {  

29.             while(flag)//重复判断标识,确认是否生产  

30.                 condition_pro.await();//本方等待  

31.   

32.             this.name=name+"......"+count++;//生产  

33.             System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产  

34.             flag=true;//控制生产\消费标识  

35.             condition_con.signal();//唤醒对方  

36.         }  

37.         finally  

38.         {  

39.             lock.unlock();//解锁,这个动作一定执行  

40.         }  

41.           

42.     }  

43.   

44.     //c1、c2共享此方法  

45.     public void getConsumer()throws InterruptedException  

46.     {  

47.         lock.lock();  

48.         try  

49.         {  

50.             while(!flag)//重复判断标识,确认是否可以消费  

51.                 condition_con.await();  

52.   

53.             System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费  

54.             flag=false;//控制生产\消费标识  

55.             condition_pro.signal();  

56.         }  

57.         finally  

58.         {  

59.             lock.unlock();  

60.         }  

61.   

62.     }  

63. }  

64.   

65. //生产者线程  

66. class Producer implements Runnable   

67. {  

68.     private Resource res;  

69.     Producer(Resource res)  

70.     {  

71.         this.res=res;  

72.     }  

73.     //复写run方法  

74.     public void run()  

75.     {  

76.         while(true)  

77.         {  

78.             try  

79.             {  

80.                 res.setProducer("商品");  

81.             }  

82.             catch (InterruptedException e)  

83.             {  

84.             }  

85.         }  

86.     }  

87. }  

88.   

89. //消费者线程  

90. class Consumer implements Runnable  

91. {  

92.     private Resource res;  

93.     Consumer(Resource res)  

94.     {  

95.         this.res=res;  

96.     }  

97.     //复写run  

98.     public void run()  

99.     {  

100.         while(true)  

101.         {  

102.             try  

103.             {  

104.                 res.getConsumer();  

105.             }  

106.             catch (InterruptedException e)  

107.             {  

108.             }  

109.         }  

110.     }  

111.   

112. }  

113.   

114. class  ProducerConsumer  

115. {  

116.     public static void main(String[] args)   

117.     {  

118.         Resource res=new Resource();  

119.   

120.         new Thread(new Producer(res)).start();//第一个生产线程 p1  

121.         new Thread(new Consumer(res)).start();//第一个消费线程 c1  

122.   

123.         new Thread(new Producer(res)).start();//第二个生产线程 p2  

124.         new Thread(new Consumer(res)).start();//第二个消费线程 c2  

125.     }  

126. }  

运行结果:部分截图

       

 

八、停止线程

        在JDK 1.5版本之前,有stop停止线程的方法,但升级之后,此方法已经过时。

那么现在我们该如果停止线程呢?

        只有一种办法,那就是让run方法结束。

1、开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。

      如:run方法中有如下代码,设置一个flag标记。  

[java] view plaincopy

1. public  void run()  

2. {  

3.     while(flag)  

4.     {     

5.         System.out.println(Thread.currentThread().getName()+"....run");  

6.     }  

7. }  

        那么只要在主函数或者其他线程中,在该线程执行一段时间后,将标记flag赋值false,该run方法就会结束,线程也就停止了。

2、上面的1方法可以解决一般情况,但是有一种特殊情况:就是当线程处于冻结状态。就不会读取到标记。那么线程就不会结束。

        当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法interrupt();

如:

[java] view plaincopy

1. class StopThread implements Runnable  

2. {  

3.     private boolean flag =true;  

4.     public  void run()  

5.     {  

6.         while(flag)  

7.         {  

8.             System.out.println(Thread.currentThread().getName()+"....run");  

9.         }  

10.     }  

11.     public void changeFlag()  

12.     {  

13.         flag = false;  

14.     }  

15. }  

16.   

17. class  StopThreadDemo  

18. {  

19.     public static void main(String[] args)   

20.     {  

21.         StopThread st = new StopThread();  

22.         Thread t1 = new Thread(st);  

23.         Thread t2 = new Thread(st);   

24.         t1.start();  

25.         t2.start();   

26.   

27.         int num = 0;  

28.         while(true)  

29.         {  

30.             if(num++ == 60)  

31.             {  

32.                 t1.interrupt();//清除冻结状态  

33.                 t2.interrupt();  

34.                 st.changeFlag();//改变循环标记  

35.                 break;  

36.             }  

37.             System.out.println(Thread.currentThread().getName()+"......."+num);  

38.         }  

39.         System.out.println("over");  

40.     }  

41. }  

结果:

       

 

九、什么时候写多线程?

        当某些代码需要同时被执行时,就用单独的线程进行封装。

示例:

[java] view plaincopy

1. class  ThreadTest  

2. {  

3.     public static void main(String[] args)   

4.     {  

5.         //一条线程  

6.         new Thread()  

7.         {  

8.             public void run()  

9.             {  

10.                 for (int x=0;x<100 ;x++ )  

11.                 {  

12.                     System.out.println(Thread.currentThread().toString()+"....."+x);  

13.                 }  

14.             }  

15.         }.start();  

16.       

17.         //又是一条线程  

18.         Runnable r= new Runnable()  

19.         {  

20.             public void run()  

21.             {  

22.                 for (int x=0;x<100 ;x++ )  

23.                 {  

24.                     System.out.println(Thread.currentThread().getName()+"....."+x);  

25.                 }  

26.             }  

27.         };  

28.         new Thread(r).start();  

29.           

30.         //可以看作主线程  

31.         for (int x=0;x<1000 ;x++ )  

32.         {  

33.             System.out.println("Hello World!");  

34.         }  

35.           

36.     }  

37. }  

 

扩展小知识:

1、join方法

        A线程执行到了b线程的.join()方法时,A线程就会等待,等B线程都执行完,A线程才会执行。(此时B和其他线程交替运行。)join可以用来临时加入线程执行。

2、setPriority()方法用来设置优先级

        MAX_PRIORITY 最高优先级10

        MIN_PRIORITY   最低优先级1

        NORM_PRIORITY 分配给线程的默认优先级

3、yield()方法可以暂停当前线程,让其他线程执行。

 

------android培训java培训、java学习型技术博客、期待与您交流!------------

 

 

 

0 0
原创粉丝点击