線程通信常用的方式有:
- wait/notify 等待
- Volatile 內存共享
- CountDownLatch 並發工具
- CyclicBarrier 並發工具
wait/notify
兩個線程交替打印奇偶數,通過wait/notify實現
public class WaitNotify {
// 狀態鎖
private static Object lock = new Object();
private static Integer i = 0;
public void odd() {
while (i < 10) {
synchronized (lock) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void even() {
while (i < 10) {
synchronized (lock) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
WaitNotify waitNotify = new WaitNotify();
Thread t1 = new Thread(() -> waitNotify.odd(), "線程1");
Thread t2 = new Thread(() -> waitNotify.even(), "線程2");
t1.start();
t2.start();
}
}
結果:
線程2 - 0
線程1 - 1
線程2 - 2
線程1 - 3
線程2 - 4
線程1 - 5
線程2 - 6
線程1 - 7
線程2 - 8
線程1 - 9
線程2 - 10
Volatile
volatile 修飾內存可見性
public class Volatile implements Runnable {
private static volatile Boolean flag = true;
@Override
public void run() {
while (flag) {
System.out.println(Thread.currentThread().getName() + " - 執行");
}
System.out.println("線程結束");
}
public static void main(String[] args) {
Thread t = new Thread(new Volatile());
t.start();
try {
Thread.sleep(5);
flag = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
結果:
Thread-0 - 執行
Thread-0 - 執行
Thread-0 - 執行
Thread-0 - 執行
Thread-0 - 執行
線程結束
CountDownLatch
CountDownLatch可以代替wait/notify的使用,並去掉synchronized,下面重寫第一個例子:
import java.util.concurrent.CountDownLatch;
public class CountDown {
private static Integer i = 0;
final static CountDownLatch countDown = new CountDownLatch(1);
public void odd() {
while (i < 10) {
if (i % 2 == 1) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
countDown.countDown();
} else {
try {
countDown.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void even() {
while (i < 10) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
countDown.countDown();
} else {
try {
countDown.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
CountDown countDown = new CountDown();
Thread t1 = new Thread(() -> countDown.odd(), "線程1");
Thread t2 = new Thread(() -> countDown.even(), "線程2");
t1.start();
t2.start();
}
}
CyclicBarrier
等待N個線程都達到某個狀態后繼續運行
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ": 准備...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("全部啟動完畢!");
}, "線程1").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ": 准備...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("全部啟動完畢!");
}, "線程2").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + ": 准備...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("全部啟動完畢!");
}, "線程3").start();
}
}
結果:
線程3: 准備...
線程2: 准備...
線程1: 准備...
全部啟動完畢!
全部啟動完畢!
全部啟動完畢!
