多线程并发库高级应用 之 多个线程之间共享数据的方式探讨
来源:互联网 发布:淘宝衣服的宣传海报 编辑:程序博客网 时间:2024/06/05 18:40
笔记摘要:
多个线程之间共享数据,按照每个线程执行代码是否相同,我们可以采取不同的处理方式,这里通过简单的卖票示例说明了当每个线程执行相同代码的情况,
对于多个线程执行不同代码的情况,处理方式比较灵活,这里主要介绍了2种方式,通过2种方式的对比和归纳,我们可以总结出在多个线程执行不同的代码
情况下,如何进行代码的设计。
一:如果每个线程执行的代码相同
可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如:卖票系统。
简单的卖票系统示例:
class Ticket implements Runnable{private int tick = 1000;Object obj = new Object();public void run(){while(true){synchronized(obj){if(tick>0){//只能try,因为run是复写了Runnable接口的run,接口的run没有抛//try{Thread.sleep(10);}catch(Exception e){}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();}}
二:如果每个线程执行的代码不同
这时候不需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享。
方式1:
将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,
这样容易实现针对该数据进行的各个操作的互斥和通信。
思想:一个类提供数据和操作数据的同步方法,另外定义两个线程通过构造函数接收并操作数据,在主函数中直接创建线程对象,即可完成操作
方式2:
将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方式也分配给外部类,以便实现对
共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。
思想:一个外部类里面有两个内部类,为了让这两个内部类共享数据,让它们都操作外部类的同一个成员,方法和数据都在这个成员身上,直接
调用方法即可完成 数据的操作
方式3:将上面两种方式的组合:
将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部
变量,每个线程的Runnable的对象作为外部类中的成员内部类或局部外部类。
技巧总结:
要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥或通信。
三、对于每个线程执行的代码不同下的3种方式,通过一个面试题来说明
需求:
设计4个线程,其中两个线程每次对j增加1,另外两个线程每次对j减少1,,写出程序
使用方式1实现:
将数据和操作共享数据的方法封装在一个类中
定义两个runnable实现类,让两个runnable都持有共享数据的引用,
在runnable的构造函数中,直接传入去操作,在实现类的run方法中调用封装类的方法
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 = 100;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;}@Overridepublic void run() {for(int i=0;i<100;i++){data.increment();}}}//减少的线程,需要传入一个共享数据class MyRunnable2 implements Runnable {private ShareData2 data;public MyRunnable2(ShareData2 data) {this.data = data;}@Overridepublic void run() {for(int i=0;i<100;i++){data.decrement();}}}
使用方式2实现
将数据和操作共享数据的方法封装在一个类中
两个runnable作为它的内部类,相对于方式1,这里没有将数据传给runnable,而是让它们自己去取,在自己的run方法中调用操作数据的方法
这里的共享变量可以定义为静态类型的成员变量,也可以定义为final类型的局部变量。
public class MultyThreadShareData {//共享数据作为外部类的成员变量//private static ShareData data = new ShareData();public static void main(String[] args){//也可以定义为final类型的局部变量final ShareData data = new ShareData();//开启4条线程for(int i=0;i<2;i++){//增加的线程new Thread(new Runnable(){@Overridepublic void run() {for(int i=0;i<100;i++){data.increment();}}}).start();//减少的线程new Thread(new Runnable(){@Overridepublic void run() {for(int i=0;i<100;i++){data.decrement();}}}).start();}}}//封装共享数据和操作共享数据方法的类class ShareData{private int j = 0;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);}}
两种方式的组合实现
public class MultyThreadShareDataTest {//private int j; public static void main(String args[]){ MultyThreadShareDataTest tt=new MultyThreadShareDataTest(); Inc inc=tt.new Inc(); Dec dec=tt.new Dec(); for(int i=0;i<2;i++){ Thread t=new Thread(inc); t.start(); t=new Thread(dec); t.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{ public void run(){ for(int i=0;i<100;i++){ inc(); } } }class Dec implements Runnable{ public void run(){ for(int i=0;i<100;i++){ dec(); } } } }
- 多线程并发库高级应用 之 多个线程之间共享数据的方式探讨
- java多线程并发库高级应用 之 多个线程之间共享数据的方式探讨
- 【Java多线程与并发库】7.多个线程之间共享数据的方式探讨
- 【Java多线程与并发库】7.多个线程之间共享数据的方式探讨
- 【Java多线程与并发库】06 多个线程之间共享数据的方式探讨
- Java多线程与并发应用-(6)-多个线程之间共享对象和数据的方式
- Java高并发编程:多个线程之间共享数据的方式探讨
- 多线程07_张孝祥-多个线程之间共享数据的方式探讨
- 多个线程之间共享数据的方式探讨
- 多线程并发库高级应用 之 线程范围内共享数据
- 多线程并发库高级应用 之 线程范围内共享数据
- 多个线程之间共享数据的方式探讨(七)
- java多线程并发库高级应用 之 线程范围内共享数据
- Java多个线程之间处理共享数据的方式
- Java多个线程之间处理共享数据的方式
- Java多个线程之间处理共享数据的方式
- Java多个线程之间处理共享数据的方式
- Java多个线程之间处理共享数据的方式
- Asp.net TreeView来构建用户选择输入的方法
- oracle SQL的HASH_VALUE 理解
- 为什么编程中发现许多时间以1970年1月1日为基准
- 无线/移动通信的发展终极目标是,实现个人通信PCN是人类通信的最高目标,它指使用各种可能的网络技术,实现任何人在任何时间、任何地点与任何人进行任何何种类的信息交换。
- 交互设计师和产品经理必读,推荐《QQ阅读 设计之路》讲述了QQ阅读的前世、今生、来世。面对这么多业界的阅读器,QQ阅读如何脱颖而出,占据市场,一起看看QQ阅读的发展过程。
- 多线程并发库高级应用 之 多个线程之间共享数据的方式探讨
- java的动态代理
- SecureCRT显示乱码解决
- 低级程序员的纠结
- PHP5.3.3源代码编译安装(Linux CentOS 5.5)
- LeetCode: Partition List
- [Leetcode] Minimum Path Sum
- Http协议详解
- ios中使用自定义的字体