用處:處理資料庫中交易管理員較為常用,所有的操作都是針對同一份資料。系統角度進行開發編程。
第一種方法,這種方法比較粗糙
public class ThreadScopeShareData { private static int data = 0; private static Map<Thread , Integer> threadData = new HashMap<Thread,Integer>(); public static void main(String[] args){ for (int i = 0; i < 2; i++) { new Thread(new Runnable(){ public void run(){ data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data :"+data); threadData.put(Thread.currentThread(),data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ data = threadData.get(Thread.currentThread()); System.out.println("A from "+ Thread.currentThread().getName()+" get data :"+data); } } static class B{ public void get(){ data = threadData.get(Thread.currentThread()); System.out.println("B from "+ Thread.currentThread().getName()+" get data :"+data); } }}
第二種方法:ThreadLocal,該類相當於一個Map
public class ThreadLocalTest { static final ThreadLocal<Integer> x = new ThreadLocal<Integer>(); public static void main(String[] args){ for (int i = 0; i < 2; i++) { new Thread(new Runnable(){ public void run(){ int data = new Random().nextInt()/10000000; System.out.println(Thread.currentThread().getName() + " has put data :"+data); x.set(data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = x.get(); System.out.println("A from "+ Thread.currentThread().getName()+" get data :"+data); } } static class B{ public void get(){ int data = x.get(); System.out.println("B from "+ Thread.currentThread().getName()+" get data :"+data); } }}
第三種方法:操作多個資料,不單單是基礎資料型別 (Elementary Data Type)。可以整合成一個實體物件,然後往ThreadLocal中set這個對象。
public class ThreadLocalTest { private static final ThreadLocal<Integer> x = new ThreadLocal<Integer>(); private static final ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); public static void main(String[] args){ for (int i = 0; i < 2; i++) { new Thread(new Runnable(){ public void run(){ int data = new Random().nextInt()/10000000; System.out.println(Thread.currentThread().getName() + " has put data :"+data); x.set(data); MyThreadScopeData myData = new MyThreadScopeData(); myData.setName(" name "+data); myData.setAge(data); myThreadScopeData.set(myData); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = x.get(); System.out.println("A from "+ Thread.currentThread().getName()+" get data :"+data); MyThreadScopeData myData = myThreadScopeData.get(); System.out.println("A from "+ Thread.currentThread().getName()+" getMydata :"+myData.getName()+","+myData.getAge()); } } static class B{ public void get(){ int data = x.get(); System.out.println("B from "+ Thread.currentThread().getName()+" get data :"+data); MyThreadScopeData myData = myThreadScopeData.get(); System.out.println("B from "+ Thread.currentThread().getName()+" getMydata :"+myData.getName()+","+myData.getAge()); } }} class MyThreadScopeData{ 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; } }
第四種方式:很優雅的處理辦法,仿單例模式處理。ThradLocal類放到實體類的背後了,設計也交給了實體類,調用者不需要關心實體類的設計,只需要get到實體類的執行個體對象即可,同一線程內,任何地方調用實體類的執行個體對象,都是同一個執行個體對象,操作的資料都是同一份,也就達到了線程內資料共用的效果。該處理方法很好的體現了物件導向的思想。
strust2也是如此的設計方式。
public class ThreadLocalTest { private static final ThreadLocal<Integer> x = new ThreadLocal<Integer>(); private static final ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); public static void main(String[] args){ for (int i = 0; i < 2; i++) { new Thread(new Runnable(){ public void run(){ int data = new Random().nextInt()/10000000; System.out.println(Thread.currentThread().getName() + " has put data :"+data); x.set(data); MyThreadScopeData.getThreadInstance().setName(" name "+data); MyThreadScopeData.getThreadInstance().setAge(data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = x.get(); System.out.println("A from "+ Thread.currentThread().getName()+" get data :"+data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out.println("A from "+ Thread.currentThread().getName()+" getMydata :"+myData.getName()+","+myData.getAge()); } } static class B{ public void get(){ int data = x.get(); System.out.println("B from "+ Thread.currentThread().getName()+" get data :"+data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out.println("B from "+ Thread.currentThread().getName()+" getMydata :"+myData.getName()+","+myData.getAge()); } }} class MyThreadScopeData{ private MyThreadScopeData(){}; private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); public static MyThreadScopeData getThreadInstance(){ MyThreadScopeData instance = map.get(); if(instance == null){ instance = new MyThreadScopeData(); map.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; } }
使用ThreadLocal類:
類似於一種棧機制,不同的線程在其有不同的記錄,當時間一久,越積越多,提供clean()方法供清理。當然其內部可以自動進行回收,不用擔心如果自己不處理會溢出問題。線程一完成,則會自動回收對應的執行個體對象的引用。如果不同的ThreadLocal對象中,同一線程有記錄,則當該線程處理完後,這些不同的ThreadLocal對象中的記錄都會被回收,除非該線程對應的執行個體對象有其他的線程所關聯操作。詳細查詢jdk文檔。
提問:如何控制線程死亡狀態?