欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java如何实现多个线程之间共享数据

程序员文章站 2022-04-02 20:46:08
目录实现多个线程之间共享数据一、 如果每个线程执行的代码相同二、 如果每个线程执行的代码不同多线程之间共享数据的方式探讨方式一:代码一致方式二:代码不一致实现多个线程之间共享数据一、 如果每个线程执行...

实现多个线程之间共享数据

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

可以使用同一个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的变量,这将被所有线程共享。

多线程之间共享数据的方式探讨

方式一:代码一致

如果每个线程执行的代码相同,可以用一个 runnable 对象,这个 runnable 对象中存放那个共享数据(卖票系统可以这样做)。

public class multithreadsharedata {
    public static void main(string[] args) {
        mysharedata sharedata=new mysharedata();
        //放入不同的线程中
        new thread(sharedata).start(); 
        new thread(sharedata).start(); 
    }
}
 
class mysharedata implements runnable {
        // 共享的数据
        private int count = 100; 
        @override
        public void run() {
            while (count > 0) {
                synchronized (this) {
                    if (count > 0) {
                        count--;
                        system.out.println(thread.currentthread().getname() + " 减了1,count还剩:" + count);
                    } 
                } 
            }
        }
    }

方式二:代码不一致

如果每个线程执行的代码不同时,就需要不同的 runnable 对象:

a. 将共享数据封装在一个对象中,然后将这个对象逐一传递给各个 runnable 对象,每个线程对共享数据操作的方法也分配到这个对象中,这样容易实现针对该数据进行的各个操作的互斥通信。

public class multithreadsharedata { 
    private int sharedata=0; 
    public static void main(string[] args) {
        sharedata data = new sharedata(); 
        new thread(new myrunnable1(data)).start(); 
        new thread(new myrunnable2(data)).start();
    } 
}
 
class myrunnable1 implements runnable{ 
    private sharedata data; 
    public myrunnable1(sharedata data){
        this.data=data;
    }
 
    @override
    public void run() {
        for(int i=0;i<100;i++){
            //对数据进行增加
            this.data.increment();
        }
    }
}
 
class myrunnable2 implements runnable{ 
    private sharedata data; 
    public myrunnable2(sharedata data){
        this.data=data;
    }
 
    @override
    public void run() {
        for(int i=0;i<100;i++){
            //对数据进行减少
            this.data.decrement();
        }
    }
}
 
/**
 将共享的数据封装成一个类
*/
class sharedata{
    //共享数据
    private int j=0; 
    public synchronized void increment(){
        this.j++;
        system.out.println(thread.currentthread().getname()+":j增加了1后j="+j);
    }
 
    public synchronized void decrement() {
        this.j--;
        system.out.println(thread.currentthread().getname()+":j减少了1后j="+j);
    }
    public int getj() {
        return j;
    }
}

b. 将 runnable 对象作为某一个类的内部类,共享数据作为这个外部类的成员变量,每个线程对共享数据的操作方法也分配到外部类中,实现共享数据的互斥和通信操作,作为内部类的各个 runnable 对象调用外部类的这些方法。

public class multithreadsharedata { 
    private int sharedata=0; 
    public static void main(string[] args) {
        multithreadsharedata m=new multithreadsharedata();
        //初始化runnable对象
        myrunnable1 myrunnable1 = m.new myrunnable1();
        myrunnable2 myrunnable2=m.new myrunnable2(); 
        //开启线程
        new thread(myrunnable1).start(); 
        new thread(myrunnable2).start();
    }
 
    private synchronized void increment(){
        this.sharedata++;
        system.out.println(thread.currentthread().getname()+":sharedata增加了1后sharedata="+sharedata);
    }
 
    private synchronized void decrement() {
        this.sharedata--;
        system.out.println(thread.currentthread().getname()+":sharedata减少了1后sharedata="+sharedata);
    }
 
    /**
     * 作为内部类的runnable对象
     */
    class myrunnable1 implements runnable{ 
        @override
        public void run() {
            for(int i=0;i<100;i++){
                increment();
            }
        }
    }
 
    class myrunnable2 implements runnable{ 
        @override
        public void run() {
            for(int i=0;i<100;i++){
                decrement();
            }
        }
    }
}

c. 以上两种方法的组合:将共享数据封装到一个对象中,每个线程对共享数据的操作方法也分配到对象中,对象作为外部类的成员变量或方法中的局部变量,每个线程的 runnable 作为成员内部类或局部内部类。

 public class multithreadsharedata {
   public static void main(string[] args) { 
       sharedata data = new sharedata(); 
       new thread(()->{
           for(int i=0;i<100;i++){
               data.increment();
           }
       }).start();
 
       new thread(()->{
           for (int j=0;j<100;j++) {
               data.decrement();
           }
       }).start();
   } 
}
 
/**
封装共享数据的对象
*/
class sharedata{
   //共享数据
   private int j=0;
 
   /**
    对共享数据进行操作的方法
   */
   public synchronized void increment(){
       this.j++;
       system.out.println(thread.currentthread().getname()+":j增加了1后j="+j);
   }
 
   public synchronized void decrement() {
       this.j--;
       system.out.println(thread.currentthread().getname()+":j减少了1后j="+j);
   }
 
   public int getj() {
       return j;
   }
}

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。