java多线程并发库高级应用 之 多个线程之间共享数据的方式探讨

来源:互联网 发布:淘宝面交交易被骗 报警 编辑:程序博客网 时间:2024/06/06 04:00

转自:http://blog.csdn.net/xushuaic/article/category/1335611

笔记摘要:

           多个线程之间共享数据,按照每个线程执行代码是否相同,我们可以采取不同的处理方式,这里通过简单的卖票示例说明了当每个线程执行相同代码的情况,

           对于多个线程执行不同代码的情况,处理方式比较灵活,这里主要介绍了2种方式,通过2种方式的对比和归纳,我们可以总结出在多个线程执行不同的代码

           情况下,如何进行代码的设计。


一:如果每个线程执行的代码相同

           可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如:卖票系统。


简单的卖票系统示例:

[java] view plain copy
  1. class Ticket implements Runnable{  
  2.     private  int tick = 1000;  
  3.     Object obj = new Object();  
  4.   
  5.     public void run(){  
  6.         while(true){  
  7.             synchronized(obj){  
  8.                 if(tick>0){  
  9.                     //只能try,因为run是复写了Runnable接口的run,接口的run没有抛  
  10.                     //try{Thread.sleep(10);}catch(Exception e){}  
  11.                     System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);  
  12.                 }  
  13.             }  
  14.         }  
  15.     }  
  16. }  
  17.   
  18.   
  19. class  TicketDemo  
  20. {  
  21.     public static void main(String[] args) {  
  22.           
  23.         //只建立了一个Ticket对象,内存中只有一个tick成员变量,所以是共享数据  
  24.         Ticket t = new Ticket();  
  25.   
  26.         Thread t1 = new Thread(t);  
  27.         Thread t2 = new Thread(t);  
  28.         Thread t3 = new Thread(t);  
  29.         Thread t4 = new Thread(t);  
  30.         t1.start();  
  31.         t2.start();  
  32.         t3.start();  
  33.         t4.start();  
  34.   
  35.     }  
  36. }  

二:如果每个线程执行的代码不同

            这时候不需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享。

 

方式1:

         将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,

         这样容易实现针对该数据进行的各个操作的互斥和通信。

思想:一个类提供数据和操作数据的同步方法,另外定义两个线程通过构造函数接收并操作数据,在主函数中直接创建线程对象,即可完成操作

 

方式2:

        将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方式也分配给外部类,以便实现对

        共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。

思想:一个外部类里面有两个内部类,为了让这两个内部类共享数据,让它们都操作外部类的同一个成员,方法和数据都在这个成员身上,直接

       调用方法即可完成 数据的操作

 

方式3:将上面两种方式的组合:

          将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部

          变量,每个线程的Runnable的对象作为外部类中的成员内部类或局部外部类。


技巧总结:

     要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥或通信。

 


 

三、对于每个线程执行的代码不同下的3种方式,通过一个面试题来说明

 

需求:

          设计4个线程,其中两个线程每次对j增加1,另外两个线程每次对j减少1,,写出程序


使用方式1实现:

       将数据和操作共享数据的方法封装在一个类中

       定义两个runnable实现类,让两个runnable都持有共享数据的引用,

       在runnable的构造函数中,直接传入去操作,在实现类的run方法中调用封装类的方法

[java] view plain copy
  1. public class MultyThreadShareMethod1 {  
  2.       
  3.     public static void main(String[] args){  
  4.       
  5.         //将数据封装到一个对象上,  
  6.         ShareData2 data1 = new ShareData2();  
  7.           
  8.         //在runnable的构造函数中直接传入去操作  
  9.         for(int i=0;i<2;i++){  
  10.         new Thread(new MyRunnable1(data1)).start();  
  11.         new Thread(new MyRunnable2(data1)).start();  
  12.         }  
  13.     }  
  14. }  
  15.   
  16.   
  17. //封装共享数据和操作共享数据方法的类  
  18. class ShareData2{  
  19.     private int j = 100;  
  20.     public synchronized void increment() {  
  21.         j++;  
  22.         System.out.println(Thread.currentThread().getName()+" inc : "+j);  
  23.     }  
  24.     public synchronized void decrement() {  
  25.         j--;  
  26.         System.out.println(Thread.currentThread().getName()+" dec : "+j);  
  27.     }  
  28. }  
  29.   
  30.   
  31. //增加的线程,需要传入一个共享数据  
  32. class MyRunnable1 implements Runnable {  
  33.       
  34.     private ShareData2 data;  
  35.     public MyRunnable1(ShareData2 data) {  
  36.         this.data = data;  
  37.     }  
  38.     @Override  
  39.     public void run() {  
  40.         for(int i=0;i<100;i++){  
  41.         data.increment();  
  42.         }  
  43.     }  
  44. }  
  45.   
  46.   
  47. //减少的线程,需要传入一个共享数据  
  48. class MyRunnable2 implements Runnable {  
  49.   
  50.   
  51.     private ShareData2 data;  
  52.     public MyRunnable2(ShareData2 data) {  
  53.         this.data = data;  
  54.     }  
  55.     @Override  
  56.     public void run() {  
  57.         for(int i=0;i<100;i++){  
  58.         data.decrement();  
  59.         }  
  60.     }  
  61. }  

使用方式2实现

        将数据和操作共享数据的方法封装在一个类中

        两个runnable作为它的内部类,相对于方式1,这里没有将数据传给runnable,而是让它们自己去取,在自己的run方法中调用操作数据的方法

       这里的共享变量可以定义为静态类型的成员变量,也可以定义为final类型的局部变量。


[java] view plain copy
  1. public class MultyThreadShareData {  
  2.       
  3.     //共享数据作为外部类的成员变量  
  4.     //private static ShareData data = new ShareData();  
  5.     public static void main(String[] args){  
  6.           
  7.         //也可以定义为final类型的局部变量  
  8.         final ShareData data = new ShareData();  
  9.           
  10.         //开启4条线程  
  11.         for(int i=0;i<2;i++){  
  12.           
  13.         //增加的线程  
  14.         new Thread(new Runnable(){  
  15.             @Override  
  16.             public void run() {  
  17.                 for(int i=0;i<100;i++){  
  18.                     data.increment();  
  19.                     }  
  20.             }  
  21.         }).start();  
  22.         //减少的线程  
  23.         new Thread(new Runnable(){  
  24.             @Override  
  25.             public void run() {  
  26.                 for(int i=0;i<100;i++){  
  27.                     data.decrement();  
  28.                 }  
  29.             }  
  30.         }).start();  
  31.         }  
  32.     }  
  33. }  
  34. //封装共享数据和操作共享数据方法的类  
  35. class ShareData{  
  36.     private int j = 0;  
  37.     public synchronized void increment() {  
  38.         j++;  
  39.         System.out.println(Thread.currentThread().getName()+" inc : "+j);  
  40.     }  
  41.     public synchronized void decrement() {  
  42.         j--;  
  43.         System.out.println(Thread.currentThread().getName()+" dec : "+j);  
  44.     }  
  45. }  


两种方式的组合实现


[java] view plain copy
  1. public class MultyThreadShareDataTest {  
  2. //  
  3. private int j;   
  4. public static void main(String args[]){   
  5.     MultyThreadShareDataTest tt=new MultyThreadShareDataTest();   
  6.         Inc inc=tt.new Inc();   
  7.         Dec dec=tt.new Dec();   
  8.           
  9.     for(int i=0;i<2;i++){   
  10.         Thread t=new Thread(inc);   
  11.        t.start();  
  12.          
  13.         t=new Thread(dec);   
  14.        t.start();   
  15.        }   
  16.    }   
  17.   
  18.     private synchronized void inc(){   
  19.        j++;   
  20.        System.out.println(Thread.currentThread().getName()+"-inc:"+j);   
  21.        }   
  22.     private synchronized void dec(){   
  23.        j--;   
  24.        System.out.println(Thread.currentThread().getName()+"-dec:"+j);   
  25.        }   
  26.       
  27.     class Inc implements Runnable{   
  28.        public void run(){   
  29.            for(int i=0;i<100;i++){   
  30.            inc();   
  31.            }   
  32.        }   
  33.     }  
  34.       
  35.     class Dec implements Runnable{   
  36.        public void run(){   
  37.            for(int i=0;i<100;i++){   
  38.            dec();   
  39.            }   
  40.        }   
  41.     }   
  42. }   

0 0