線程之間共享數據
Java 裡面進行多線程通信的主要方式就是共享內存的方式,共享內存主要的關注點有兩個:可見性和有序性原子性。Java 內存模型(JMM)解決了可見性和有序性的問題,而鎖解決了原子性的問題,理想情況下我們希望做到“同步”和“互斥”。有以下常規實現方
8.1 將數據抽象成一個類,並將數據的操作作為這個類的方法
1. 將數據抽象成一個類,並將對這個數據的操作作為這個類的方法,這麼設計可以和容易做到同步,只要在方法上加”synchronized“
MyData
public class MyData {
private int j=0;
public synchronized void add(){
j++;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
}
public synchronized void dec(){
j--;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
}
public int getData(){
return j;
}
}
AddRunnable
public class AddRunnable implements Runnable{
MyData data;
public AddRunnable(MyData data){
this.data= data;
} public void run() {
data.add();
}
}
DecRunnable
public class DecRunnable implements Runnable {
MyData data;
public DecRunnable(MyData data){ this.data = data;
} public void run() {
data.dec();
}
}
public static void main(String[] args) {
MyData data = new MyData();
Runnable add = new AddRunnable(data);
Runnable dec = new DecRunnable(data);
for(int i=0;i<2;i++){ new Thread(add).start();
new Thread(dec).start();
}
}
8.2 Runnable 對象作為一個類的內部類
將Runnable 對象作為一個類的內部類,共享數據作為這個類的成員變量,每個線程對共享數據的操作方法也封裝在外部類,以便實現對數據的各個操作的同步和互斥,作為內部類的各個Runnable 對象調用外部類的這些方法。
MyData
public class MyData { private int j=0;
public synchronized void add(){ j++;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
} public synchronized void dec(){ j--;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
} public int getData() {
return j;
}
}
TestThread
public class TestThread { public static void main(String[] args) {
final MyData data = new MyData(); for(int i=0;i<2;i++)
{
new Thread(new Runnable(){ public void run() { data.add(); }}).start();
new Thread(new Runnable(){ public void run() { data.dec(); }}).start();
}
} }
8.3 ThreadLocal
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,ThreadLocal 的作用是提供線程內的局部變量,這種變量在線程的生命週期內起作用,減少同一個線程內多個函數或者組件之間一些公共變量的傳遞的複雜度。
8.3.1 ThreadLocalMap(線程的一個屬性)
1. 每個線程中都有一個自己的ThreadLocalMap 類對象,可以將線程自己的對象保持到其中,各管各的,線程可以正確的訪問到自己的對象。
2. 將一個共用的ThreadLocal 靜態實例作為key,將不同對象的引用保存到不同線程的ThreadLocalMap 中,然後在線程執行的各處通過這個靜態ThreadLocal 實例的get()方法取得自己線程保存的那個對象,避免了將這個對象作為參數傳遞的麻煩。
3. ThreadLocalMap 其實就是線程裡面的一個屬性,它在Thread 類中定義
ThreadLocal.ThreadLocalMap threadLocals = null;
線程之間共享數據
Java 裡面進行多線程通信的主要方式就是共享內存的方式,共享內存主要的關注點有兩個:可見性和有序性原子性。Java 內存模型(JMM)解決了可見性和有序性的問題,而鎖解決了原子性的問題,理想情況下我們希望做到“同步”和“互斥”。有以下常規實現方
8.1 將數據抽象成一個類,並將數據的操作作為這個類的方法
1. 將數據抽象成一個類,並將對這個數據的操作作為這個類的方法,這麼設計可以和容易做到同步,只要在方法上加”synchronized“
MyData
public class MyData {
private int j=0;
public synchronized void add(){
j++;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
}
public synchronized void dec(){
j--;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
}
public int getData(){
return j;
}
}
AddRunnable
public class AddRunnable implements Runnable{
MyData data;
public AddRunnable(MyData data){
this.data= data;
} public void run() {
data.add();
}
}
DecRunnable
public class DecRunnable implements Runnable {
MyData data;
public DecRunnable(MyData data){ this.data = data;
} public void run() {
data.dec();
}
}
public static void main(String[] args) {
MyData data = new MyData();
Runnable add = new AddRunnable(data);
Runnable dec = new DecRunnable(data);
for(int i=0;i<2;i++){ new Thread(add).start();
new Thread(dec).start();
}
}
8.2 Runnable 對象作為一個類的內部類
將Runnable 對象作為一個類的內部類,共享數據作為這個類的成員變量,每個線程對共享數據的操作方法也封裝在外部類,以便實現對數據的各個操作的同步和互斥,作為內部類的各個Runnable 對象調用外部類的這些方法。
MyData
public class MyData { private int j=0;
public synchronized void add(){ j++;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
} public synchronized void dec(){ j--;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
} public int getData() {
return j;
}
}
TestThread
public class TestThread { public static void main(String[] args) {
final MyData data = new MyData(); for(int i=0;i<2;i++)
{
new Thread(new Runnable(){ public void run() { data.add(); }}).start();
new Thread(new Runnable(){ public void run() { data.dec(); }}).start();
}
} }
8.3 ThreadLocal
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,ThreadLocal 的作用是提供線程內的局部變量,這種變量在線程的生命週期內起作用,減少同一個線程內多個函數或者組件之間一些公共變量的傳遞的複雜度。
8.3.1 ThreadLocalMap(線程的一個屬性)
1. 每個線程中都有一個自己的ThreadLocalMap 類對象,可以將線程自己的對象保持到其中,各管各的,線程可以正確的訪問到自己的對象。
2. 將一個共用的ThreadLocal 靜態實例作為key,將不同對象的引用保存到不同線程的ThreadLocalMap 中,然後在線程執行的各處通過這個靜態ThreadLocal 實例的get()方法取得自己線程保存的那個對象,避免了將這個對象作為參數傳遞的麻煩。
3. ThreadLocalMap 其實就是線程裡面的一個屬性,它在Thread 類中定義
ThreadLocal.ThreadLocalMap threadLocals = null;
8.3.2 使用場景
最常見的ThreadLocal 使用場景為用來解決數據庫連接、Session 管理等。public class ThreadLocalTest {
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try { if (s == null) {
s = getSessionFactory().openSession(); threadSession.set(s); }
}
catch (HibernateException ex)
{
throw new InfrastructureException(ex);
} return s;
}
}
線程之間共享數據
Java 裡面進行多線程通信的主要方式就是共享內存的方式,共享內存主要的關注點有兩個:可見性和有序性原子性。Java 內存模型(JMM)解決了可見性和有序性的問題,而鎖解決了原子性的問題,理想情況下我們希望做到“同步”和“互斥”。有以下常規實現方
8.1 將數據抽象成一個類,並將數據的操作作為這個類的方法
1. 將數據抽象成一個類,並將對這個數據的操作作為這個類的方法,這麼設計可以和容易做到同步,只要在方法上加”synchronized“
MyData
public class MyData {
private int j=0;
public synchronized void add(){
j++;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
}
public synchronized void dec(){
j--;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
}
public int getData(){
return j;
}
}
AddRunnable
public class AddRunnable implements Runnable{
MyData data;
public AddRunnable(MyData data){
this.data= data;
} public void run() {
data.add();
}
}
DecRunnable
public class DecRunnable implements Runnable {
MyData data;
public DecRunnable(MyData data){ this.data = data;
} public void run() {
data.dec();
}
}
public static void main(String[] args) {
MyData data = new MyData();
Runnable add = new AddRunnable(data);
Runnable dec = new DecRunnable(data);
for(int i=0;i<2;i++){ new Thread(add).start();
new Thread(dec).start();
}
}
8.2 Runnable 對象作為一個類的內部類
將Runnable 對象作為一個類的內部類,共享數據作為這個類的成員變量,每個線程對共享數據的操作方法也封裝在外部類,以便實現對數據的各個操作的同步和互斥,作為內部類的各個Runnable 對象調用外部類的這些方法。
MyData
public class MyData { private int j=0;
public synchronized void add(){ j++;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
} public synchronized void dec(){ j--;
System.out.println("線程"+Thread.currentThread().getName()+"j 為:"+j);
} public int getData() {
return j;
}
}
TestThread
public class TestThread { public static void main(String[] args) {
final MyData data = new MyData(); for(int i=0;i<2;i++)
{
new Thread(new Runnable(){ public void run() { data.add(); }}).start();
new Thread(new Runnable(){ public void run() { data.dec(); }}).start();
}
} }
8.3 ThreadLocal
ThreadLocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲,ThreadLocal 的作用是提供線程內的局部變量,這種變量在線程的生命週期內起作用,減少同一個線程內多個函數或者組件之間一些公共變量的傳遞的複雜度。
8.3.1 ThreadLocalMap(線程的一個屬性)
1. 每個線程中都有一個自己的ThreadLocalMap 類對象,可以將線程自己的對象保持到其中,各管各的,線程可以正確的訪問到自己的對象。
2. 將一個共用的ThreadLocal 靜態實例作為key,將不同對象的引用保存到不同線程的ThreadLocalMap 中,然後在線程執行的各處通過這個靜態ThreadLocal 實例的get()方法取得自己線程保存的那個對象,避免了將這個對象作為參數傳遞的麻煩。
3. ThreadLocalMap 其實就是線程裡面的一個屬性,它在Thread 類中定義
ThreadLocal.ThreadLocalMap threadLocals = null;
8.3.2 使用場景
最常見的ThreadLocal 使用場景為用來解決數據庫連接、Session 管理等。public class ThreadLocalTest {
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try { if (s == null) {
s = getSessionFactory().openSession(); threadSession.set(s); }
}
catch (HibernateException ex)
{
throw new InfrastructureException(ex);
} return s;
}
}