多线程之3-------多个线程访问共享数据的方式

来源:互联网 发布:南方公园知乎 编辑:程序博客网 时间:2024/06/08 15:35

本文先从一个面试题说起:

设计4个线程,其中两个线程每次对  j  +1, 另外两个线程对 j-1, 

分析:  这里 j 看作是一个共享数据

从现实例子来看,可以扩展到卖票,假设有100张票, 分5个窗口卖。这个问题也涉及到多线程

解决:  

分两种情况  

  1  如果每个线程执行的代码相同,可以使用同一个Runnable 对象,此Runnable 对象存在共享数据,  如:  卖票程序可以这么做,因为都是执行减少的过程

代码

public class MultiThreadShareData {

       public static void main(String[] args) {
          ShareData1 data1 = new ShareData1();
          new Thread(data1).start();
          new Thread(data1).start();
       }
     

     class ShareData1   implements Runnable  {
           private int count = 100;
          @Override
         public void run() {
              while(true){
                    count--;
          }

     }

}

注意这里只用了data1  这一个Runnable 对象

2  每个线程执行的代码不同,就需要用不同的Runnable  对象,有两种方式来实现这些Runnable 对象之间的数据共享。

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

代码如下,注意  data1 对象为共享数据

public class MultiThreadShareData { 
 public static void main(String[] args) {
  ShareData1 data1 = new ShareData1();
  new Thread(new MyRunnable1(data1)).start();
  new Thread(new MyRunnable2(data1)).start();
 }

}
 class MyRunnable1 implements Runnable{
  private ShareData1 data1;
  public MyRunnable1(ShareData1 data1){
   this.data1 = data1;
  }
  public void run() {
   data1.decrement();   
  }
 } 
 class MyRunnable2 implements Runnable{
  private ShareData1 data1;
  public MyRunnable2(ShareData1 data1){
   this.data1 = data1;
  }
  public void run() {
   data1.increment();
  }
 }

 class ShareData1{    
         private int j = 0;
         public synchronized void increment(){
             j++;
         }
  
         public synchronized void decrement(){
             j--;
        }
 }

第二种  将这些Runnable 对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,

以便实现对共享数据进行的各个操作的互斥与通信, 作为内部类的每个Runnable 对象调用外部类的这些方法.

代码如下:

public class MultiThreadShareData { 
 public static void main(String[] args) {
  ShareData1 data2 = new ShareData1();
  new Thread(new MyRunnable1(data2)).start();
  new Thread(new MyRunnable2(data2)).start();
 
  final ShareData1 data1 = new ShareData1();
  new Thread(new Runnable(){
   @Override
   public void run() {
    data1.decrement();
   }
  }).start();
  new Thread(new Runnable(){
   @Override
   public void run() {
    data1.increment();
   }
  }).start();
 }
}
 class MyRunnable1 implements Runnable{
  private ShareData1 data1;
  public MyRunnable1(ShareData1 data1){
   this.data1 = data1;
  }
  public void run() {
   data1.decrement();
  }
 }
 class MyRunnable2 implements Runnable{
  private ShareData1 data1;
  public MyRunnable2(ShareData1 data1){
   this.data1 = data1;
  }
  public void run() {
   data1.increment();
  }
 }

 class ShareData1{    
  private int j = 0;
  public synchronized void increment(){
   j++;
  }
  public synchronized void decrement(){
   j--;
  }
 }

一个内部类,如果放在static 方法里,不能访问全局变量,  要访问需要将变量用static 修饰,或者是将变量改为局部变量,用final 修饰

现在回到刚开始的问题, 代码如下:

public class ShareDataTest {
 int j = 0;
 public static void main(String args[]){
  ShareDataTest  t = new ShareDataTest();
  Inc inc = t.new Inc();
  Dec dec = t.new Dec();
  
  /**
   *  这里循环表示依次启动两次,每次启动两个线程,
   *  一个增加的线程,一个减少的线程
   *  这里  对j的增减没有考虑先后顺序
   */
  for(int i=0;i<2;i++){
   Thread th = new Thread(inc);
   th.start();
   th = new Thread(dec);
   th.start();
  }
 }
  private synchronized void inc(){
  j++;
  System.out.println(Thread.currentThread().getName()+" inc: "+j);  
 }
 private synchronized void dec(){
  j--;
  System.out.println(Thread.currentThread().getName()+" dec: "+j);
 }
 class  Inc implements Runnable{  
  @Override
  public void run() {
   for(int i=0;i<100;i++){
    inc();
   }
  }
 }
 class  Dec implements Runnable{
   @Override
   public void run() {
    for(int i=0;i<100;i++){
     dec();
    }
   }
 }
}

运行效果如下