Java 多个线程之间共享数据

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

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

class Ticket implements Runnable{  
    private  int tick = 20;  
    Object obj = new Object();  
  
    public void run(){  
        while(true){  
            synchronized(obj){  
                if(tick>0){  
                    //只能try,因为run是复写了Runnable接口的run,接口的run没有抛  
                    try{Thread.sleep(100);}catch(Exception e){}  //使用sleep不然执行每个线程都会占用完毕
                    System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);  
                }  
            }  
        }  
    }  
}  
  
class  TicketDemo  
{  
    public static void main(String[] args) {  
          
        //只建立了一个Ticket对象,内存中只有一个tick成员变量,所以是共享数据  
        Ticket t = new Ticket();  
  
        Thread t1 = new Thread(t);  
        Thread t2 = new Thread(t);  
        Thread t3 = new Thread(t);  
        Thread t4 = new Thread(t);  
        t1.start();  
        t2.start();  
        t3.start();  
        t4.start();  
    }  
} 

输出结果

Thread-0....sale : 20
Thread-1....sale : 19
 .......
Thread-3....sale : 2
Thread-3....sale : 1

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

1、具体实现

将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

思想: 一个类提供数据和操作数据的同步方法,另外定义两个线程通过构造函数接收并操作数据,在主函数中直接创建线程对象,即可完成操作(可以实现两个内部类,不用构造方法传值,使用final定义data局部变量

例如: 设计4个线程,其中两个线程每次对j增加1,另外两个线程每次对j减少1

public class MultyThreadShareMethod1 {  
      
    public static void main(String[] args){  
      
        //将数据封装到一个对象上,  
        ShareData2 data1 = new ShareData2();  
          
        //在runnable的构造函数中直接传入去操作  
        for(int i=0;i<2;i++){  
        new Thread(new MyRunnable1(data1)).start();  
        new Thread(new MyRunnable2(data1)).start();  
        }  
    }  
}  
 
//封装共享数据和操作共享数据方法的类  
class ShareData2{  
    private int j = 10;  
    public synchronized void increment() {  
        j++;  
        System.out.println(Thread.currentThread().getName()+" inc : "+j);  
    }  
    public synchronized void decrement() {  
        j--;  
        System.out.println(Thread.currentThread().getName()+" dec : "+j);  
    }  
}  
   
//增加的线程,需要传入一个共享数据  
class MyRunnable1 implements Runnable {  
      
    private ShareData2 data;  
    public MyRunnable1(ShareData2 data) {  
        this.data = data;  
    }  
    @Override  
    public void run() {  
        for(int i=0;i<10;i++){  
        data.increment();  
        }  
    }  
}  
  
//减少的线程,需要传入一个共享数据  
class MyRunnable2 implements Runnable {   
    private ShareData2 data;  
    public MyRunnable2(ShareData2 data) {  
        this.data = data;  
    }  
    @Override  
    public void run() {  
        for(int i=0;i<10;i++){  
        data.decrement();  
        }  
    }  
}  

输出结果

Thread-0 inc : 11
...
Thread-1 dec : 10

2、 技巧总结

要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥或通信。极端且简单的方式,即在任意一个类中定义一个static的变量,这将被所有线程共享。

本文都来自博客多个线程之间共享数据的方式探讨的精简版,详细的分析参考博客

你可能感兴趣的:(Java基础)