Java並發基礎09. 多個線程間共享數據問題


先看一個多線程間共享數據的問題:

設計四個線程,其中兩個線程每次對data增加1,另外兩個線程每次對data減少1。

從問題來看,很明顯涉及到了線程間通數據的共享,四個線程共享一個 data,共同操作一個 data。我們先把上面這個問題放在一邊,慢慢分析多個線程之間共享數據的一些情況,從最簡單開始,分類分析完了后,到時候也好解決上面這個問題了。

1. 每個線程執行的任務相同

這是最簡單的一種情況,比如賣票,幾個線程共同操作記錄票數的那個變量,任務都是使它減一。針對這種情況,我們只需要寫一個類實現 Runnable 接口即可,在 run() 方法中對這個票進行減一,然后將這個 Runnable 扔給多個線程去執行,自然它們就操作同一個data了。看一下代碼:

public class MultiThreadShareData {

	public static void main(String[] args) {
		
		ShareData task = new ShareData(); //一個類實現了Runnable接口
		
		for(int i = 0; i < 4; i ++) {	//四個線程來賣票		
			new Thread(task).start();
		}

	}

}

class ShareData implements Runnable {

	private int data = 100;
	@Override
	public void run() { //賣票,每次一個線程進來,先判斷票數是否大於0
//		while(data > 0) {
			synchronized(this) {
				if(data > 0) {
					System.out.println(Thread.currentThread().getName() + ": " + data);
					data--;
				}
			}
//		}
	}
}

這很好理解,也很容易實現,四個線程賣了4張票。運行結果為:

Thread-0: 100
Thread-3: 99
Thread-2: 98
Thread-1: 97

2. 每個線程執行不同的任務

就如上面那個題目所描述的,兩個線程執行 data 增,兩個線程執行 data 減。針對這種情況,我們要實現兩個 Runnable 了,因為很明顯有兩個不同的任務了,一個任務執行 data 增,另一個任務執行 data 減。為了便於維護,可以將兩個任務方法放到一個類中,然后將 data 也放在這個類中,然后傳到不同的 Runnabl e中,即可完成數據的共享。如下:

public class MultiThreadShareData {

	public static void main(String[] args) {
		
		ShareData task = new ShareData(); //公共數據和任務放在task中

		for(int i = 0; i < 2; i ++) { //開啟兩個線程增加data
			
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					task.increment();
				}
			}).start();
		}
		
		for(int i = 0; i < 2; i ++) { //開啟兩個線程減少data
			
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					task.decrement();
				}
			}).start();
		}			
	}
}	


class ShareData /*implements Runnable*/ {

	private int data = 0;
	public synchronized void increment() { //增加data
		System.out.println(Thread.currentThread().getName() + ": before : " + data);
		data++;
		System.out.println(Thread.currentThread().getName() + ": after : " + data);
	}
	
	public synchronized void decrement() { //減少data
		System.out.println(Thread.currentThread().getName() + ": before : " + data);
		data--;
		System.out.println(Thread.currentThread().getName() + ": after : " + data);
	}
}

看一下打印結果:

Thread-0: before : 0
Thread-0: after : 1
Thread-1: before : 1
Thread-1: after : 2
Thread-2: before : 2
Thread-2: after : 1
Thread-3: before : 1
Thread-3: after : 0

這樣寫的好處是兩個任務方法可以直接在方法名上進行同步操作,這種模式的好處在前面的博文中已經有說過了,封裝的好。

最后總結一下,多個線程之間共享數據主要關注兩點就行:一是什么任務?幾個任務?二是幾個線程?記住 一點:幾個任務和幾個線程是沒有關系的!100個線程可以執行一個任務,也可以執行2個任務,3個任務……

如果只有一個任務,那說明多個線程執行一個任務,我們只要實現一個 Runnable 接口,把公共 data 放進 Runnable,把任務放進去 run() 中即可(任務注意要同步),然后開啟N個線程去執行這個任務即可;如果有M個任務,那我們新建一個專門執行任務的類,把公共的 data 放進類中,把任務作為類中的同步方法即可,然后開啟N個線程,每個線程中扔一個 Runnable,按照要求執行任務類中的方法即可。

到這里,讀者應該能體會到任務和線程的分離了,這種思想也算是面向對象的一種吧,思路很清晰。

多個線程之間共享數據就總結這么多,如有問題,歡迎交流,我們共同進步~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM