1. 程式人生 > 其它 >執行緒間通訊方式

執行緒間通訊方式

執行緒間通訊的模型有兩種:共享記憶體和訊息傳遞

方式一:使用volatile關鍵字

基於volatile關鍵字來實現執行緒間相互通訊是使用共享記憶體的思想,大致意思就是多個執行緒同時監聽一個變數,當這個變數發生變化的時候 ,執行緒能夠感知並執行相應的業務。這也是最簡單的一種實現方式

public class TestSync {
// 定義一個共享變數來實現通訊,它需要是volatile修飾,否則執行緒不能及時感知
static volatile boolean notice = false;

public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 實現執行緒A
Thread threadA = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("執行緒A向list中新增一個元素,此時list中的元素個數為:" + list.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5)
notice = true;
}
});
// 實現執行緒B
Thread threadB = new Thread(() -> {
while (true) {
if (notice) {
System.out.println("執行緒B收到通知,開始執行自己的業務...");
break;
}
}
});
// 需要先啟動執行緒B
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再啟動執行緒A
threadA.start();
}
}

方式二:使用Object類的wait() 和 notify() 方法
眾所周知,Object類提供了執行緒間通訊的方法:wait()、notify()、notifyaAl(),它們是多執行緒通訊的基礎,而這種實現方式的思想自然是執行緒間通訊。

注意: wait和 notify必須配合synchronized使用,wait方法釋放鎖,notify方法不釋放鎖

public class TestSync {
public static void main(String[] args) {
// 定義一個鎖物件
Object lock = new Object();
List<String> list = new ArrayList<>();
// 實現執行緒A
Thread threadA = new Thread(() -> {
synchronized (lock) {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("執行緒A向list中新增一個元素,此時list中的元素個數為:" + list.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5)
lock.notify();// 喚醒B執行緒
}
}
});
// 實現執行緒B
Thread threadB = new Thread(() -> {
while (true) {
synchronized (lock) {
if (list.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("執行緒B收到通知,開始執行自己的業務...");
}
}
});
// 需要先啟動執行緒B
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再啟動執行緒A
threadA.start();
}
}

方式三:使用JUC工具類 CountDownLatch
jdk1.5之後在java.util.concurrent包下提供了很多併發程式設計相關的工具類,簡化了我們的併發程式設計程式碼的書寫,***CountDownLatch***基於AQS框架,相當於也是維護了一個執行緒間共享變數state

public class TestSync {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(1);
List<String> list = new ArrayList<>();
// 實現執行緒A
Thread threadA = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("執行緒A向list中新增一個元素,此時list中的元素個數為:" + list.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5)
countDownLatch.countDown();
}
});
// 實現執行緒B
Thread threadB = new Thread(() -> {
while (true) {
if (list.size() != 5) {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("執行緒B收到通知,開始執行自己的業務...");
break;
}
});
// 需要先啟動執行緒B
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再啟動執行緒A
threadA.start();
}
}

使用 ReentrantLock 結合 Condition

public class TestSync {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

List<String> list = new ArrayList<>();
// 實現執行緒A
Thread threadA = new Thread(() -> {
lock.lock();
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("執行緒A向list中新增一個元素,此時list中的元素個數為:" + list.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5)
condition.signal();

}
lock.unlock();
});
// 實現執行緒B
Thread threadB = new Thread(() -> {
lock.lock();
if (list.size() != 5) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("執行緒B收到通知,開始執行自己的業務...");
lock.unlock();
});
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadA.start();
}
}

方式五:基本LockSupport實現執行緒間的阻塞和喚醒

LockSupport是一種非常靈活的實現執行緒間阻塞和喚醒的工具,使用它不用關注是等待執行緒先進行還是喚醒執行緒先執行,但是得知道執行緒的名字。

public class TestSync {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 實現執行緒B
final Thread threadB = new Thread(() -> {
if (list.size() != 5) {
LockSupport.park();
}
System.out.println("執行緒B收到通知,開始執行自己的業務...");
});
// 實現執行緒A
Thread threadA = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("執行緒A向list中新增一個元素,此時list中的元素個數為:" + list.size());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5)
LockSupport.unpark(threadB);
}
});
threadA.start();
threadB.start();
}
}

{ 一點塵塵 }