1. 程式人生 > >android 執行緒範圍內共享變數以及ThreadLocal的使用

android 執行緒範圍內共享變數以及ThreadLocal的使用

執行緒在java中是一個重頭戲,算是比較難的一快,特別是併發哪一塊,關於併發這一塊,專案上幾乎也沒用到,今天是講執行緒範圍內的共享變數,突然聽到這個概念,可能心裡有點發愣,打個簡單比方:有三個執行緒,每一個產生一個數據,有三個模組分別取獲取每個執行緒產生的資料,在java中其實已經有現成的類給我們解決了此方案 哪就是ThreadLoacl類,我們先不用java提供的類先手動解決下

package com.kge;
import java.util.Random;

public class ThreadLocalDemo {
	private static int data = 0;
		public static void main(String[] args) {
			for(int i=0;i<4;i++){
				new Thread(new Runnable() {
					@Override
					public void run() {
						data = new Random().nextInt();
						System.out.println(Thread.currentThread().getName()+"has put data:"+data);
						new A().get();
						new B().get();
					}
				}){}.start();
			}
		}
		static class A{
			public void get(){
				System.out.println("A from"+Thread.currentThread().getName()+"data="+data);
			}
		}
		static class B{
			public  void get(){
				System.out.println("B from"+Thread.currentThread().getName()+"data="+data);
			}
		}
}

列印結果:


看到這個結果 此時心都涼了,怎麼和我預期的效果不一樣,其實仔細看程式碼不能發現這是執行緒安全問題導致的,稍微分析一下就知道了程式執行是這樣的,


發現程式並不是按照我們正常從一而終這樣順序執行的,每當執行緒執行到給data變數賦值時,另外一個執行緒就進來了,依次類推,這樣會導致前生成的data變數值會被後的值覆蓋,哪我們就換個方案,我們把每一個執行緒產生的資料和這個執行緒一一對應,哪就用到集合儲存了,程式碼修改後如下:

public class ThreadLocalDemo {
	private static int data = 0;
	private static Map<Thread,Integer> maps = new HashMap<Thread,Integer>();
		public static void main(String[] args) {
			for(int i=0;i<4;i++){
				new Thread(new Runnable() {
					@Override
					public void run() {
						data = new Random().nextInt();
						System.out.println(Thread.currentThread().getName()+"has put data:"+data);
						maps.put(Thread.currentThread(),data);
						new A().get();
						new B().get();
					}
				}){}.start();
			}
		}
		static class A{
			public void get(){
				int data = maps.get(Thread.currentThread());
				System.out.println("A from"+Thread.currentThread().getName()+"data="+data);
			}
		}
		static class B{
			public  void get(){
				int data = maps.get(Thread.currentThread());
				System.out.println("B from"+Thread.currentThread().getName()+"data="+data);
			}
		}
}


發現這個方案也是有問題的,問題出在哪呢?和之前分析的到底一樣,哪現在怎麼改呢?此刻無限的沉思之中,怎麼辦?還有什麼辦法呢?其實只要解決一個問題 就可以把所有的問題解決掉,哪就是變數data屬於每個執行緒自己的屬性,這個時候就是考察你基本功好不好的關鍵時刻了,其實只要把data變數不要做成類變數就可以了,

int data = new Random().nextInt();

好了問題解決了,現在改用java給我們提供好的ThreadLocal類

public class ThreadLocalDemo {
	private static int data = 0;
	static ThreadLocal<Integer> local = new ThreadLocal<Integer>();
		public static void main(String[] args) {
			for(int i=0;i<4;i++){
				new Thread(new Runnable() {
					@Override
					public void run() {
						int data = new Random().nextInt();
						System.out.println(Thread.currentThread().getName()+"has put data:"+data);
						local.set(data);
						new A().get();
						new B().get();
					}
				}){}.start();
			}
		}
		static class A{
			public void get(){
				data = local.get();
				System.out.println("A from"+Thread.currentThread().getName()+"data="+data);
			}
		}
		static class B{
			public  void get(){
				data = local.get();
				System.out.println("B from"+Thread.currentThread().getName()+"data="+data);
			}
		}
}
看看多麼簡單就那麼幾行程式碼搞定,這就是java語言的強大之處,什麼事都給你封裝好了,如果執行緒共享有很多個變數,這個時候怎麼辦,哪直接把這些變數封裝到一個類中,因為ThreadLcoal類可以儲存任意的值!