Java如何实现多个线程之间共享数据
这篇文章主要介绍了Java如何实现多个线程之间共享数据,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
目录
实现多个线程之间共享数据
一、 如果每个线程执行的代码相同
二、 如果每个线程执行的代码不同
多线程之间共享数据的方式探讨
方式一:代码一致
方式二:代码不一致
实现多个线程之间共享数据
一、 如果每个线程执行的代码相同
可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如:卖票系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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 对象中存放那个共享数据(卖票系统可以这样做)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 对象,每个线程对共享数据操作的方法也分配到这个对象中,这样容易实现针对该数据进行的各个操作的互斥通信。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 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 对象调用外部类的这些方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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 作为成员内部类或局部内部类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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; } } |
总之,要同步互斥的几段代码最好放在几个独立的方法中,这些方法再放入一个类中,这样比较容易实现它们之间的同步互斥和通信。
以上为个人经验,希望能给大家一个参考
原文链接:https://blog.csdn.net/qq_35988274/article/details/102796867