多線程之間的通信
- 線程通信概念:線程是操作系統(tǒng)中獨(dú)立的個(gè)體,但這些個(gè)體如果不經(jīng)過特殊處理就不能成為一個(gè)整體夹抗,線程間的通信就成為整體的必用方式之一膘格。當(dāng)線程存在通信指揮谷婆,系統(tǒng)間的交互性會(huì)更強(qiáng)大,在提高CPU利用率的同時(shí)還會(huì)使開發(fā)人員對(duì)線程任務(wù)在處理過程中進(jìn)行有效的把控與監(jiān)督径玖。
- 使用wait/notify 方法實(shí)現(xiàn)線程間的通信痴脾。(注意這兩個(gè)方法都是Object類的方法,換句話說Java為所有的對(duì)象都提供了這兩個(gè)方法)
- wait 和 notify 必須配合synchronized 關(guān)鍵字使用梳星。
- wait 方法釋放鎖赞赖,notify 方法不釋放鎖
使用輪詢的方式通信
public static void main(String[] args) {
final ListAddTest1 list = new ListAddTest1();
Thread thread_1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
list.add();
System.out.println("當(dāng)前線程:" + Thread.currentThread().getName() + " 添加一個(gè)元素滚朵!");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "Thread-1");
Thread thread_2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (list.size() == 5) {
System.out.println("當(dāng)前線程收到通知:" + Thread.currentThread().getName() + " list size = 5 線程停止..");
throw new RuntimeException();
}
}
}
}, "Thread-2");
thread_1.start();
thread_2.start();
}
使用notify 和 wait 方法通信
- 如上述的代碼,thread-2 線程一種處于一種輪詢的方式前域,我們可以修改Java中多線程通信的方式來改造辕近, 使用notify 和 wait.
- 注意必須配合 synchronized 關(guān)鍵字來使用,否則會(huì)報(bào) java.lang.IllegalMonitorStateException 非法監(jiān)控異常
- 必須先啟動(dòng) wait 方法的線程话侄,因?yàn)閚otify 方法不會(huì)釋放鎖亏推,先啟動(dòng)notify 方法的線程,執(zhí)行到 notify 方法的時(shí)候年堆,并沒有線程在 wait.
public static void main(String[] args) {
final ListAddUseNotifyAndWait list = new ListAddUseNotifyAndWait();
final Object lock = new Object();
Thread thread_1 = new Thread(new Runnable() {
@Override
public void run() {
// synchronized (lock) {
try {
for (int i = 0; i < 10; i++) {
list.add();
System.out.println("當(dāng)前線程:" + Thread.currentThread().getName() + " 添加一個(gè)元素吞杭!");
Thread.sleep(500);
if (list.size() == 5) {
System.out.println("已經(jīng)發(fā)出通知!");
lock.notify();// notify 方法不會(huì)釋放鎖
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// }
}
}, "Thread-1");
Thread thread_2 = new Thread(new Runnable() {
@Override
public void run() {
try {
// synchronized (lock) {
if (list.size() != 5) {
System.out.println("Thread-2進(jìn)入...");
lock.wait();// wait 方法會(huì)釋放鎖
}
System.out.println("當(dāng)前線程收到通知:" + Thread.currentThread().getName() + " list size = 5 線程停止..");
throw new RuntimeException();
// }
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread-2");
// 需要先啟動(dòng) thread_2 , 因?yàn)槿绻葐?dòng) thread_1变丧, 那么 notify 方法不會(huì)釋放鎖芽狗,
// t1線程完全執(zhí)行完才會(huì)釋放鎖, 當(dāng)t1到notify 方法的時(shí)候,并沒有 其他線程在 wait
thread_2.start();
thread_1.start();
}
使用CountDownLatch 閉鎖來進(jìn)行通信
- 在使用notify 和 wait 來進(jìn)行通信的時(shí)候還有一個(gè)問題痒蓬,在程序中我們必須等 thread-1 執(zhí)行完成童擎,才會(huì)釋放鎖來通知 thread-2,這會(huì)造成不實(shí)時(shí)的問題攻晒。如果需要程序在 list.size 為5 的時(shí)候顾复,就立馬執(zhí)行 thread-2 中的線程的話,我們就可以使用 CountDownLatch 的方式來進(jìn)行通信
final CountDownLatch countDownLatch = new CountDownLatch(1);
Thread thread_1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
list.add();
System.out.println("當(dāng)前線程:" + Thread.currentThread().getName() + " 添加一個(gè)元素鲁捏!");
Thread.sleep(500);
if (list.size() == 5) {
System.out.println("已經(jīng)發(fā)出通知芯砸!");
countDownLatch.countDown();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread-1");
Thread thread_2 = new Thread(new Runnable() {
@Override
public void run() {
try {
if (list.size() != 5) {
System.out.println("Thread-2進(jìn)入...");
countDownLatch.await();
}
System.out.println("當(dāng)前線程收到通知:" + Thread.currentThread().getName() + " list size = 5 線程停止..");
throw new RuntimeException();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread-2");
thread_1.start();
thread_2.start();
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者