线程间通信总结

1、volatile关键字

volatile可见性,线程间共享同一变量,volatile修饰,保证线程间可见性。

import java.util.Date;

public class OTest {
    
    private static volatile boolean flag = false;

    public static void main(String[] args) {

        Thread threadB = new Thread(() -> {
            while (!flag) {
                try {
                    Thread.sleep(1000);
                    System.out.println(new Date());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        threadB.start();


        Thread threadA = new Thread(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
        });
        threadA.start();
    }
}

2、使用 Object 类的 wait()/notify()
Object 类提供了线程间通信的方法:wait()、notify()、notifyAll(),它们是多线程通信的基础,而这种实现方式的思想自然是线程间通信。
注意:wait/notify 必须配合 synchronized 使用,wait 方法释放锁,notify 方法不释放锁。wait 是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify(),notify并不释放锁,只是告诉调用过wait()的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放,调用 wait() 的一个或多个线程就会解除 wait 状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

public class OTest2 {

    public static void main(String[] args) {
        //定义一个锁对象
        Object lock = new Object();
        // 线程A
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("线程A释放锁,唤醒B");
                    lock.notify();
                }
            }
        });
        //线程B
        Thread threadB = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("线程B等待前处理");
                    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();
    }
}

由输出结果,在线程 A 发出 notify() 唤醒通知之后,依然是走完了自己线程的业务之后,线程 B 才开始执行,正好说明 notify() 不释放锁,而 wait() 释放锁。

3、使用JUC工具类 CountDownLatch
jdk1.5 之后在java.util.concurrent包下提供了很多并发编程相关的工具类,简化了并发编程代码的书写,CountDownLatch 基于 AQS 框架,相当于也是维护了一个线程间共享变量 state。


import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class OTest2 {

    public static void main(String[] args) {

        List<String> param = Arrays.asList("a", "b", "c");
        CountDownLatch countDownLatch = new CountDownLatch(param.size());

        long start = System.currentTimeMillis();
        for (int i = 0; i < param.size(); i++) {
            Thread thread = new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
            thread.start();
        }
        try {
            countDownLatch.await();
            System.out.println("所有线程执行完毕,耗时:" + (System.currentTimeMillis() - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4、Condition 线程间通信
Condition的强大之处在于它可以为多个线程间建立不同的Condition, 使用synchronized/wait()只有一个阻塞队列,notifyAll会唤起所有阻塞队列下的线程,而使用lock/condition,可以实现多个阻塞队列,signalAll只会唤起某个阻塞队列下的阻塞线程。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class OTest4 {

    public static void main(String[] args) {
        //定义一个锁对象
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        // 线程A
        Thread threadA = new Thread(() -> {
            reentrantLock.lock();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("线程A释放锁,唤醒B");
                condition.signalAll();
                reentrantLock.unlock(); // 需要主动释放锁
            }
        });
        //线程B
        Thread threadB = new Thread(() -> {
            reentrantLock.lock();
            try {
                System.out.println("线程B等待前处理");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程B收到通知,开始执行自己的业务...");
        });
        //需要先启动线程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //再启动线程A
        threadA.start();
    }
}

5、基本 LockSupport 实现线程间的阻塞和唤醒
LockSupport 是一种非常灵活的实现线程间阻塞和唤醒的工具,使用它不用关注是等待线程先进行还是唤醒线程先运行,但是得知道线程的名字。


import java.util.concurrent.locks.LockSupport;

public class OTest5 {

    public static void main(String[] args) {
        //线程B
        Thread threadB = new Thread(() -> {
            System.out.println("线程B等待前处理");
            LockSupport.park();
            System.out.println("线程B收到通知,开始执行自己的业务...");
        });
        Thread threadA = new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程A释放锁,唤醒B");
            if (threadB != null) {
                LockSupport.unpark(threadB);
            }
        });
        //需要先启动线程B
        threadB.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //再启动线程A
        threadA.start();
    }
}
posted @   倔强的老铁  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示