JAVA 併發程式設計-執行緒範圍內共享變數(五)
執行緒範圍內共享變數要實現的效果為:
多個物件間共享同一執行緒內的變數
未實現執行緒共享變數的demo:
package cn.itcast.heima2; import java.util.HashMap; import java.util.Map; import java.util.Random; public class ThreadScopeShareData { private static int data = 0; // private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>(); public static void main(String[] args) { //共啟動2個執行緒 for(int i=0;i<2;i++){ //啟動一個執行緒 new Thread(new Runnable(){ @Override public void run() { data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data :" + data); //以當前執行緒為key值放入到map中,當取值時根據各自的執行緒取各自的資料 // threadData.put(Thread.currentThread(), data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ // int data = threadData.get(Thread.currentThread()); System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data); } } static class B{ public void get(){ // int data = threadData.get(Thread.currentThread()); System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data); } } }
執行結果:
通過打印出的結果可以看出,當Thread-0獲取了一個隨機數,修改了data的值,正在睡眠的時候,Thread-1又獲取了一個隨機數,同樣修改了data的值,然後Thread-1呼叫了靜態內部類A和B的get方法,實際上此時的data已經是Thread-1拿到的隨機數了。
當然,我們可以通過增加synchronized加鎖來控制執行緒的執行。讓Thread-0執行完方法之前,Thread-1不能修改data的值。
此外,還可以使用另外幾種方法來獲取執行緒執行時變數賦予的真正值。
執行緒範圍內共享變數實現方式:
Map實現方式:
package cn.itcast.heima2; import java.util.HashMap; import java.util.Map; import java.util.Random; public class ThreadScopeShareData { private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>(); public static void main(String[] args) { //共啟動2個執行緒 for(int i=0;i<2;i++){ //啟動一個執行緒 new Thread(new Runnable(){ @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data :" + data); //以當前執行緒為key值放入到map中,當取值時根據各自的執行緒取各自的資料 threadData.put(Thread.currentThread(), data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data); } } static class B{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data); } } }
執行結果:
ThreadLocal方式:
package cn.itcast.heima2; import java.util.Random; public class ThreadLocalTest { private static ThreadLocal<Integer> x = 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 data = new Random().nextInt(); 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); } } }
存在的問題:一個ThreadLocal代表一個變數,故其中只能放一個數據,如果你有兩個變數要執行緒範圍內共享,則要定義兩個ThreadLocal。如下為解決方案:
擴充套件方式-單例方式處理物件:
package cn.itcast.heima2;
import java.util.Random;
public class ThreadLocalTest {
// 方式一
// private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ " has put data :" + data);
// 方式一 ThreadLocal
// x.set(data);
// 方式二 new物件方式,將多個屬性放到物件中
// MyThreadScopeData myData = new MyThreadScopeData();
// myData.setName("name" + data);
// myData.setAge(data);
// myThreadScopeData.set(myData);
// 方式三 使用單例模式
MyThreadScopeData.getThreadInstance().setName("name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
// 方式一 ThreadLocal
// int data = x.get();
// System.out.println("A from " + Thread.currentThread().getName()
// + " get data :" + data);
// 方式二 new物件方式,將多個屬性放到物件中
// MyThreadScopeData myData = myThreadScopeData.get();;
// System.out.println("A from " + Thread.currentThread().getName()
// + " getMyData: " + myData.getName() + "," +
// myData.getAge());
// 方式三 使用單例模式
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.get();;
// System.out.println("B from " + Thread.currentThread().getName()
// + " getMyData: " + myData.getName() + "," +
// myData.getAge());
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
}
class MyThreadScopeData{
private MyThreadScopeData(){}
private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
public static /*synchronized*/ 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;
}
}
總結:
synchronized和使用ThreadLocal均可以解決以上的問題,只是這是兩種不同的方式,synchronized是依賴鎖的機制一個執行完後另一個再執行。ThreadLocal會為每一個執行緒維護一個和該執行緒繫結的變數的副本,從而隔離了多個執行緒的資料,每一個執行緒都擁有自己的變數副本,從而也就沒有必要對該變數進行同步了。
概括起來說,對於多執行緒資源共享的問題,同步機制採用了“以時間換空間”的方式,而ThreadLocal採用了“以空間換時間”的方式。前者僅提供一份變數,讓不同的執行緒排隊訪問,而後者為每一個執行緒都提供了一份變數,因此可以同時訪問而互不影響。
當然ThreadLocal並不能替代同步機制,兩者面向的問題領域不同。同步機制是為了同步多個執行緒對相同資源的併發訪問,是為了多個執行緒之間進行通訊的有效方式;而ThreadLocal是隔離多個執行緒的資料共享,從根本上就不在多個執行緒之間共享資源(變數),這樣當然不需要對多個執行緒進行同步了。
ThreadLocal的應用:
在業務邏輯層需要呼叫多個Dao層的方法,我們要保證事務(jdbc事務)就要確保他們使用的是同一個資料庫連線.那麼如何確保使用同一個資料庫連線呢?
相關推薦
JAVA 併發程式設計-執行緒範圍內共享變數(五)
執行緒範圍內共享變數要實現的效果為:多個物件間共享同一執行緒內的變數未實現執行緒共享變數的demo:package cn.itcast.heima2; import java.util.HashMap; import java.util.Map; import java.u
(三) Java多執行緒詳解之執行緒範圍內共享變數及ThreadLocal類使用
執行緒範圍內共享變數 HashTable方式實現 在開發中經常會遇到一種情況:有一個變數會被多個執行緒訪問,但是要確保同個執行緒內訪問的是同一個物件,Hashtable方式實現程式碼如下: public class ThreadExample5 {
多執行緒與併發----執行緒範圍內共享變數
執行緒範圍內共享資料圖解:mport java.util.HashMap; import java.util.Map; import java.util.Random; public class Th
Java多執行緒之執行緒範圍內共享變數的概念與作用
要實現執行緒範圍內的資料共享,就是說不管是A模組還是B模組,如果它們現在在同一個執行緒上執行,它們操作的資料應該是同一個,下面的做法就不行: package javaplay.thread.test; import java.util.Random; public
05_張孝祥_Java多執行緒_執行緒範圍內共享變數的概念與作用
概念 可以將每個執行緒用到的資料與對應的執行緒號存放到一個map集合中,使用資料時從這個集合中根據執行緒號獲取對應執行緒的資料,就可以實現執行緒範圍內共享相同的變數。 程式碼 Runnable中的run()方法裡面執行Thread.currentThrea
執行緒範圍內共享變數的概念與作用
package cn.cblue.heima2; import java.util.HashMap; import java.util.Map; import java.util.Rando
android 執行緒範圍內共享變數以及ThreadLocal的使用
執行緒在java中是一個重頭戲,算是比較難的一快,特別是併發哪一塊,關於併發這一塊,專案上幾乎也沒用到,今天是講執行緒範圍內的共享變數,突然聽到這個概念,可能心裡有點發愣,打個簡單比方:有三個執行緒,
ThreadLocal實現執行緒範圍內共享變數
1.多執行緒範圍內訪問共享物件和資料的方式。 1).如果每個執行緒要執行的程式碼一樣,可以使用同一個Runnable物件,這個Runnable物件中有共享資料,例如:買票系統。 2).每一個執行緒要執行的程式碼不一樣,這樣就需要使用多個Runnable物件了。有以下幾
Java併發庫(五、六、七):執行緒範圍內共享資料、ThreadLocal、共享資料的三種方法
深切懷念傳智播客張孝祥老師,特將其代表作——Java併發庫視訊研讀兩遍,受益頗豐,記以後閱 05. 執行緒範圍內共享變數的概念與作用 執行緒範圍內共享資料圖解: 程式碼演示: class ThreadScopeShareData { 三個模組共享資料,主執
java多執行緒併發庫高階應用 之 執行緒範圍內共享資料
轉自:http://blog.csdn.net/xushuaic/article/category/1335611 筆記摘要: 所謂執行緒範圍內共享資料,即對於相同的程式程式碼,多個模組在同一個執行緒中執行時要共享一份資料,而在另外執行緒中執行時又共
多執行緒併發庫高階應用 之 執行緒範圍內共享資料
筆記摘要: 所謂執行緒範圍內共享資料,即對於相同的程式程式碼,多個模組在同一個執行緒中執行時要共享一份資料,而在另外執行緒中執行時又共享另外一份資料, API中為我們提供了一個操作執行緒範圍內共享資料的類ThreadLocal,對於執行緒範
(十三)java併發程式設計--執行緒中斷
1、自己新增執行緒退出標誌位。 如下程式碼所示: package thread_priority; /** * Created by fang on 2017/12/3. * */ public class MyThread imple
(十二)java併發程式設計--執行緒優先順序
執行緒的優先順序並不能保證現成的執行次序。只不過,優先順序高的執行緒獲取CPU資源的概率較大,優先順序低的也並不是沒有機會執行。 優先順序用1-10的整數表示,數值越大優先順序越高,預設
(十五)java併發程式設計--執行緒的死鎖(deadlock)
執行緒在作業系統使用不同的資源,一般以以下方式使用這些資源。 1)請求一個資源。 2)使用這個資源。 3)釋放資源。 1、什麼是死鎖? 死鎖的情況是,一些執行緒被阻塞,每個執行緒都擁有一個資源,並且等待另外一個程序以獲取另外的一個資源。 想了想
(十六)java併發程式設計--執行緒的死鎖解決方案(生產者和消費者幾種實現方式)
上一篇中,主要了解了什麼時候死鎖,並且提出死鎖的一個解決方案,多個鎖要按照一定的順序來。 本片主要是利用生產者消費者模式解決執行緒的死鎖。 多執行緒生產者和消費者一個典型的多執行緒程式。一個生產者生產提供消費的東西,但是生產速度和消費速度是不同的。這就需要讓
(十四)java併發程式設計--執行緒的阻塞
java中我們可以使用執行緒類的三種方式來阻止執行緒的執行。 執行緒的狀態圖如下(圖片來自網路): 1、yield() yield英文的意思是屈服,如同其意,當前執行緒屈服,暫停,讓同等優先順序的執行緒執行。 yield()方法可以暫停當前
Java併發程式設計--執行緒安全問題與解決方案
本文簡介: 用多執行緒開發的人都知道,在多執行緒的開發過程中有可能會出現執行緒安全問題(專業術語叫記憶體可見性問題),但並不一定每次都會出現。出現這樣的情況,也會另開發者頭皮發麻,無從下手,接下來我們會慢慢深入,揭開多執行緒的神祕面紗。 本文主要介紹了Jav
[Java併發程式設計]-執行緒的六種狀態及其狀態轉換
轉載請註明:http://blog.csdn.net/UniKylin/article/details/45050823 1.執行緒自身資訊 執行緒執行的過程會產生很多資訊,這些資訊都儲存在Thread類中的成員變數裡面,常見的有: a.執行緒的ID是唯
java併發程式設計—— 執行緒池原理 詳解 ThreadPoolExecutor
為什麼要使用執行緒池 降低資源消耗: 通過重複利用執行緒,減少執行緒的建立銷燬損耗的資源 提高響應速度: 任務到達時,不用重新建立執行緒,之間可以使用已經建立好的執行緒執行 提高執行緒的可管理性 執行緒池實現分析 我們使用如下的demo來一步一
JAVA併發程式設計——執行緒協作通訊(二)
執行緒間的協作 在前面我們瞭解了很多關於同步(互斥鎖)的問題,下面來看一下執行緒之間的協作。這裡主要說一下Java執行緒中的join()、sleep()、yield()、wait()、notify()和notifyAll()方法。其中wait()、notify(