android 執行緒範圍內共享變數以及ThreadLocal的使用
阿新 • • 發佈:2019-01-27
執行緒在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類
看看多麼簡單就那麼幾行程式碼搞定,這就是java語言的強大之處,什麼事都給你封裝好了,如果執行緒共享有很多個變數,這個時候怎麼辦,哪直接把這些變數封裝到一個類中,因為ThreadLcoal類可以儲存任意的值!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); } } }