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的变量,这将被所有线程共享。
多线程之间共享数据的方式探讨
方式一:代码一致
如果每个线程执行的代码相同,可以用一个 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; } }
总之,要同步互斥的几段代码最好放在几个独立的方法中,这些方法再放入一个类中,这样比较容易实现它们之间的同步互斥和通信。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。