多線程信息共享
- 線程類
– 通過繼承Thread或實現Runnable接口
– 通過start方法,調用run方法,run方法工作
– 線程run結束後,線程退出 - 粗粒度:子線程與子線程之間、main線程之間缺乏交流
- 細粒度:線程之間有信息交流通訊
– 通過共享變量達到信息共享
– JDK原生庫暫不支持發送消息(類似MPI並行庫直接發送消息)
MPI是一個信息傳遞應用程序接口,包括協議和語義說明。MPI的目標是高性能,大規模性,和可移植性。MPI在今天仍爲高性能計算的主要模型 - 通過共享變量在多個線程中共享消息
– static變量
– 同一個Runnable類的成員變量
/**
* @ClassName:ThreadDemo0
* @Description:
* @author: Torey
*/
public class ThreadDemo0 {
public static void main(String[] args){
for (int i = 0; i < 4; i++) {
new TestThread0().start();
}
}
}
class TestThread0 extends Thread{
//每個線程賣2張,4個線程賣8張
private int tickets=2;
//所有線程賣2張,4個線程賣2張
//private static int tickets=2;
@Override
public void run() {
while (true){
if (tickets>0) {
tickets--;
System.out.println(Thread.currentThread().getName() + " tickets=" + tickets);
}else {break;}
}
}
}
/**
* @ClassName:ThreadDemo1
* @Description:
* @author: Torey
*/
public class ThreadDemo1 {
public static void main(String[] args){
TestDemo1 testDemo1=new TestDemo1();
//兩個線程共享一個對象
new Thread(testDemo1).start();
new Thread(testDemo1).start();
}
}
class TestDemo1 implements Runnable{
private volatile static int tickets=4;
public void run() {
while (true) {
if (tickets>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;
System.out.println(Thread.currentThread().getName()
+" :"+tickets);
}else {
break;
}
}
}
}
多線程共享問題
- 多線程信息共享問題
– 工作緩存副本
– 關鍵步驟缺乏加鎖限制 - i++,並非原子性操作
– 讀取主存i(正本)到工作緩存(副本)中
– 每個CPU執行(副本)i+1操作
– CPU將結果寫入到緩存(副本)中
– 數據從工作緩存(副本)刷到主存(正本)中
工作緩存發(副本):是每個線程獨有的內存空間 - 變量副本問題的解決方法
– 採用volatile關鍵字修飾變量
– 保證不同線程對共享變量操作時的可見性
volatile關鍵字代碼示例
如下:不加volatile的變量,當主線程將flag設置爲false後,子線程不能及時的讀取到,導致while一直執行
加volatile的變量,當主線程將flag設置爲false後,子線程可以及時的讀取到,while循環跳出
源碼如下:
/**
* @ClassName:ThreadDemo2
* @Description:volatile變量的使用
* @author: Torey
*/
public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
TestThread2 t = new TestThread2();
t.start();
Thread.sleep(2000);
t.flag=false;
System.out.println("main thread is exiting");}}
class TestThread2 extends Thread{
// boolean flag=true;//子線程不會停止,while裏用的是工作緩存中的flag值,值是true,而主存裏flag值爲false,主存裏的不能及時刷新到工作緩存中
volatile boolean flag=true;//用volatile修飾的變量可以及時在各線程裏面通知
@Override
public void run() {
int i=0;
while (flag){i++;}
System.out.println("test thread is exiting");
}
}