1. 程式人生 > >ThreadLocal實現執行緒範圍內共享變數

ThreadLocal實現執行緒範圍內共享變數

 1.多執行緒範圍內訪問共享物件和資料的方式。

 1).如果每個執行緒要執行的程式碼一樣,可以使用同一個Runnable物件,這個Runnable物件中有共享資料,例如:買票系統。

 2).每一個執行緒要執行的程式碼不一樣,這樣就需要使用多個Runnable物件了。有以下幾種方式:

 (1).將需要共享的資料單獨封裝在一個物件中,建立該物件的例項逐一傳遞給Runnable物件。

<span style="font-size:18px;"><span style="font-size:24px;"> final ShareData data =new ShareData();
		new Thread(
				new Runnable(){

			@Override
			public void run() {
				while(true){
					data.increment();
				}
				
			}}).start();
		new Thread(
				new Runnable(){

			@Override
			public void run() {
				while(true){
					data.decrement();
				}
				
			}}).start();
	}
	
	

}
class ShareData{
private int j ;
	public synchronized void increment(){
	j++;
	System.out.println(Thread.currentThread().getName()+ " increment "+j);
}
public synchronized void decrement(){
	j--;
	System.out.println(Thread.currentThread().getName()+ " decrement "+j);
}
	
}</span></span>
  (2).將需要共享的資料封裝在Runnable物件中。
<span style="font-size:18px;"><span style="font-size:24px;">class Runnable1 implements Runnable{

	@Override
	public void run() {
//	...
		
	}
	
}
class Runnable2 implements Runnable
{

	@Override
	public void run() {
//		...
		
	}
	
}</span></span>

 (3).將Runnable物件作為某一個類的內部類, 共享資料作為這個類的外部類。

 2).極端的一種方式,即在任意一個類中定義一個static變數,這將被所有執行緒共享。

 2.執行緒範圍內的共享資料。

   對於同一份程式程式碼,多個模組在同一個執行緒中執行時要共享一份資料,而在另外一個執行緒執行時又共享另外一份資料。
  

 自已來做的話,也很好做。

<span style="font-size:18px;"><span style="font-size:24px;">package com.hb;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadLocal {

	private final static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();

	public static void main(String[] args) {
		// 建立三個執行緒,並且生產三個資料
		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					int data = new Random().nextInt();
					threadData.put(Thread.currentThread(), data);
					System.out.println(Thread.currentThread().getName()
							+ " has put data " + data);
					new A().get();
					new B().get();

				}

			}).start();

		}
	}

	// 模組A
	static class A {
		int data = threadData.get(Thread.currentThread());

		public void get() {
			System.out.println("A from " + Thread.currentThread().getName()
					+ " get data " + data);
		}
	}

	// 模組B
	static class B {

		int data = threadData.get(Thread.currentThread());

		public void get() {
			System.out.println("B from " + Thread.currentThread().getName()
					+ " get data " + data);

		}
	}

}
</span></span>

java對這個threadData進行了封裝,ThreadLocal相當於一個Map,每一個執行緒呼叫全域性ThreadLocal物件的set方法,就相當於往其內部的map增加一條記錄。key分別是各自的執行緒。

<span style="font-size:18px;">package com.hb;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadLocalTest {

//	private final static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
 private final static ThreadLocal<Integer> threadData=new ThreadLocal();
	public static void main(String[] args) {
		// 建立三個執行緒,並且生產三個資料
		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					int data = new Random().nextInt();
//					threadData.put(Thread.currentThread(), data);
					threadData.set(data);
					System.out.println(Thread.currentThread().getName()
							+ " has put data " + data);
					new A().get();
					new B().get();

				}

			}).start();

		}
	}

	// 模組A
	static class A {
		int data = threadData.get();//threadData.get(Thread.currentThread());

		public void get() {
			System.out.println("A from " + Thread.currentThread().getName()
					+ " get data " + data);
		}
	}

	// 模組B
	static class B {

		int data = threadData.get();//threadData.get(Thread.currentThread());

		public void get() {
			System.out.println("B from " + Thread.currentThread().getName()
					+ " get data " + data);

		}
	}

}
</span>

值得注意的是一個ThreadLocal代表一個變數,故其中只能放一個數據。那我想放多個怎麼辦?打包唄。

l實現對ThreadLocal變數的封裝,讓外界不要直接操作ThreadLocal變數。 對基本型別的資料的封裝,這種應用相對很少見。 對物件型別的資料的封裝,比較常見,即讓某個類針對不同執行緒分別建立一個獨立的例項物件。
<span style="font-size:18px;">package com.hb;

import java.util.Random;

import com.hb.ThreadLocalTest.A;
import com.hb.ThreadLocalTest.B;

public class ThreadLocalTest2 {

	
		public static void main(String[] args) {
			// 建立三個執行緒,並且生產三個資料
			for (int i = 0; i < 3; i++) {
				new Thread(new Runnable() {

					@Override
					public void run() {
						int data = new Random().nextInt();
					 MyThreadScopeData.getThreadInstance().setName("name"+data);
					 MyThreadScopeData.getThreadInstance().setAge(data);
						System.out.println(Thread.currentThread().getName()
								+ " has put data " + data);
						new A().get();
						new B().get();

					}

				}).start();

			}	
		
	}
	static class A{
		public void get(){
			MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
			System.out.println("A from "+Thread.currentThread().getName()
					+ " get  name "+myData.getName()+", get age "+myData.getAge());
		}
	}
	static class B{
		public void get(){
			MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
			System.out.println("B from "+Thread.currentThread().getName()
					+ " get  name "+myData.getName()+", get age "+myData.getAge());
		}
	}

}
class MyThreadScopeData{
	//將ThreadLocal封裝在此。
	private MyThreadScopeData(){}
	private static ThreadLocal<MyThreadScopeData> maps=new ThreadLocal<MyThreadScopeData>();
	public static MyThreadScopeData getThreadInstance(){
		MyThreadScopeData	instance =maps.get();
		if(instance == null){
			instance =new MyThreadScopeData();
			maps.set(instance);
		}
		return instance;
	}
	
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}
</span>