一、JVM内置通信方式
1.synchronized + wait() / notify() / notifyAll()
Object 类的 wait()、notify() 和 notifyAll() 方法。这是 Java 中最基础的线程间通信方式,基于对象的监视器(锁)机制
public class WaitNotifyExample {
private int count = 0;
private static final int MAX = 5;
private final Object lock = new Object();
// 生产者:生产数据
public void produce() throws InterruptedException {
synchronized (lock) {
// 当缓冲区满时,等待
while (count == MAX) {
lock.wait(); // 释放锁,进入等待
}
count++;
System.out.println("生产后:" + count);
lock.notifyAll(); // 通知消费者
}
}
// 消费者:消费数据
public void consume() throws InterruptedException {
synchronized (lock) {
// 当缓冲区空时,等待
while (count == 0) {
lock.wait(); // 释放锁,进入等待
}
count--;
System.out.println("消费后:" + count);
lock.notifyAll(); // 通知生产者
}
}
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
// 启动生产者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
example.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// 启动消费者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
example.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
2.volatile
volatile可以保证不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,新值对其他线程来说立即可见
class VolatileDemo {
private static volatile boolean running = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (running) { } // 一直循环
System.out.println("线程停止");
});
t.start();
Thread.sleep(1000);
running = false; // 修改变量,t 线程立刻感知到
}
}
3.join()
让一个线程等待另一个线程执行完毕
class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
System.out.println("子线程执行任务中...");
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println("子线程执行完毕");
});
t.start();
t.join(); // 主线程等待 t 线程执行完
System.out.println("主线程继续执行");
}
}
二、并发工具类方式(java.util.concurrent
提供)
1.Lock + Condition
Lock接口提供了比synchronized更灵活的锁机制,Condition接口可以配合Lock实现线程间的等待/通知
import java.util.concurrent.locks.*;
class ConditionDemo {
private static final Lock lock = new ReentrantLock();
private static final Condition condition = lock.newCondition();
private static boolean ready = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock();
try {
while (!ready) {
condition.await(); // 等待
}
System.out.println("t1 收到通知");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
Thread t2 = new Thread(() -> {
lock.lock();
try {
ready = true;
condition.signal(); // 唤醒一个等待线程
System.out.println("t2 发送通知");
} finally {
lock.unlock();
}
});
t1.start();
try { Thread.sleep(100); } catch (InterruptedException e) {}
t2.start();
}
}
2.CountDownLatch
一个同步辅助类,允许一个或多个线程等待其他线程完成操作,一次性的,倒计时归零后不可重置。
CountDownLatch(int count):构造函数,指定需要等待的线程数量
countDown():减少计数器的值
await()::使当前线程等待,直到计数器的值为 0
import java.util.concurrent.*;
class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " 完成任务");
latch.countDown();
}, "工作线程" + i).start();
}
latch.await(); // 等待计数归零
System.out.println("主线程继续执行");
}
}
3.CyclicBarrier
一个同步辅助类,允许一组线程相互等待,直到所有线程都到达某个公共屏障点,可以重复使用。
CyclicBarrier(int parties, Runnable barrierAction):构造函数,指定参与的线程数量和所有线程到达屏障点后要执行的操作
await:使当前线程等待,直到所有线程都到达屏障点
import java.util.concurrent.*;
class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("所有线程到达屏障,开始执行"));
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 到达屏障");
try { barrier.await(); } catch (Exception e) {}
System.out.println(Thread.currentThread().getName() + " 继续执行");
}).start();
}
}
}
4.Semaphore
一个计数信号量,它可以控制同时访问特定资源的线程数量。
Semaphore(int permits):构造函数,指定信号量的初始许可数量
acquire():获取一个许可,如果没有可用许可则阻塞
release():释放一个许可
import java.util.concurrent.*;
class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2); // 最多 2 个线程同时执行
for (int i = 1; i <= 5; i++) {
int id = i;
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("线程" + id + " 获取许可");
Thread.sleep(1000);
System.out.println("线程" + id + " 释放许可");
} catch (InterruptedException e) {}
finally {
semaphore.release();
}
}).start();
}
}
}
5.Exchanger
用来在两个线程之间交换数据,如果只有一个线程调用了 exchange(),它会一直阻塞,直到另一个线程也调用
import java.util.concurrent.Exchanger;
public class ExchangerDemo {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
new Thread(() -> {
try {
String msg = "来自线程A的数据";
System.out.println("线程A准备交换:" + msg);
String result = exchanger.exchange(msg);
System.out.println("线程A收到:" + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
String msg = "来自线程B的数据";
System.out.println("线程B准备交换:" + msg);
String result = exchanger.exchange(msg);
System.out.println("线程B收到:" + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}