線程範圍內的共享變量是指對同一個變量,幾個線程同時對它進行寫和讀操做,而同一個線程讀到的數據就是它本身寫進去的數據。java
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package
com.model.elgin.thread; import java.util.Random; public class NotSharedVarThread { private static int data; public static void main( String [] args) { for ( int i = 0 ; i < 2 ; i++) { new Thread( new Runnable() { @Override public void run() { data= new Random().nextInt( 10000 ); System.out.println(Thread.currentThread().getName() + "將data修改成:" +data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ System.out.println(Thread.currentThread().getName() + "-A類中data的值爲:" + data); } } static class B{ public void get(){ System.out.println(Thread.currentThread().getName() + "-B類中data的值爲:" + data); } } } |
運行結果:安全
從結果能夠看出,線程0將線程1修改後的data值覆蓋了,而且輸出的結果是線程1中修改的值。dom
那麼該如何來解決這個問題呢?ide
使用同步代碼塊,將變量修改以及訪問的代碼加鎖,線程0訪問結束才容許線程1來修改data的值,代碼以下:函數
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package
com.model.elgin.thread; import java.util.Random; public class NotSharedVarThread { private static int data; public static void main( String [] args) { for ( int i = 0 ; i < 2 ; i++) { new Thread( new Runnable() { @Override public void run() { synchronized (NotSharedVarThread. class ) { data= new Random().nextInt( 10000 ); System.out.println(Thread.currentThread().getName() + "將data修改成:" +data); new A().get(); new B().get(); } } }).start(); } } static class A{ public void get(){ System.out.println(Thread.currentThread().getName() + "-A類中data的值爲:" + data); } } static class B{ public void get(){ System.out.println(Thread.currentThread().getName() + "-B類中data的值爲:" + data); } } } |
運行結果:測試
從結果能夠看出,線程1結束以後線程0纔開始修改data的值。spa
經過Map的特性,將key爲當前線程,value爲對應的值。.net
測試代碼:線程
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package
com.model.elgin.thread; import java.util.HashMap; import java.util.Map; import java.util.Random; public class NotSharedVarThread { private static Map<Thread,Integer> data= new HashMap<Thread, Integer>(); public static void main( String [] args) { for ( int i = 0 ; i < 2 ; i++) { new Thread( new Runnable() { @Override public void run() { int value= new Random().nextInt( 10000 ); data.put(Thread.currentThread(),value); System.out.println(Thread.currentThread().getName()+ "將data中的值修改成:" + value); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ System.out.println(Thread.currentThread().getName() + "-A類中data的值爲:" + data.get(Thread.currentThread())); } } static class B{ public void get(){ System.out.println(Thread.currentThread().getName() + "-B類中data的值爲:" + data.get(Thread.currentThread())); } } } |
運行結果:對象
ThreaLocal類在維護變量時,實際使用了當前線程(Thread)中的一個叫作 ThreadLocalMap的獨立副本(Thread的成員變量),每一個線程能夠獨立的修改屬於本身的副本而不會相互影響,從而實現了線程之間的隔離,避免了線程訪問實例變量發生衝突的問題。
示例代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package
com.model.elgin.thread; import java.util.HashMap; import java.util.Map; import java.util.Random; public class NotSharedVarThread { private static ThreadLocal<Integer> data= new ThreadLocal<Integer>(); public static void main( String [] args) { for ( int i = 0 ; i < 2 ; i++) { new Thread( new Runnable() { @Override public void run() { int value= new Random().nextInt( 10000 ); data.set(value); System.out.println(Thread.currentThread().getName()+ "將線程對應的value保存到ThreadLocal對象中" + value); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ System.out.println(Thread.currentThread().getName() + "-A類中data的值爲:" + data.get()); } } static class B{ public void get(){ System.out.println(Thread.currentThread().getName() + "-B類中data的值爲:" + data.get()); } } } |
運行結果:
1) ThreadLocal是一個Java類,經過對當前線程中局部變量的操做來解決不一樣線程的訪問變量的衝突問題。因此,ThreadLocal提供了線程安全的共享機制,每一個線程都擁有各自的副本(ThreadLocalMap實例)
2) Java中的synchronized是一個關鍵字,它依靠JVM的鎖機制來實現臨界區的函數或者變量在訪問時的原子性。在同步機制中,經過對象的鎖機制來保證同一時刻只有一個線程訪問變量。
同步機制採起了以「以時間換空間」的方式,提供一個變量,讓線程排隊訪問。而ThreadLocal則是採用了以「空間換取時間」的方式,爲每個線程都提供一份變量副本,從而實現同時訪問而互不影響。