线程通信的4种方式
线程通信常用的方式有:
- 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: 准备...
全部启动完毕!
全部启动完毕!
全部启动完毕!