您的位置:首页 > 其它

多线程并发库高级应用 之 多个线程之间共享数据的方式探讨

2012-12-05 13:08 891 查看

笔记摘要:

多个线程之间共享数据,按照每个线程执行代码是否相同,我们可以采取不同的处理方式,这里通过简单的卖票示例说明了当每个线程执行相同代码的情况,

对于多个线程执行不同代码的情况,处理方式比较灵活,这里主要介绍了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;
	}
	@Override
	public 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;
	}
	@Override
	public 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(){
			@Override
			public void run() {
				for(int i=0;i<100;i++){
					data.increment();
					}
			}
		}).start();
		//减少的线程
		new Thread(new Runnable(){
			@Override
			public 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(); 
	       } 
	   } 
	} 
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: