线程通信

Posted myarticles

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程通信相关的知识,希望对你有一定的参考价值。

wait()与notify()

首先考虑下面的情景,一个线程必须要等另外一个线程执行完才能继续执行,可以设置一个变量,第二个线程一直监控它,当第一个线程执行完后修改这个变量的值,第二个线程监控到值发生了改变然后继续执行,如下代码

public class Demo {
    private volatile boolean signal = false;

    public static void main(String[] args) {
        Demo d = new Demo();

        // 第一个线程
        new Thread(() -> {
            System.out.println("准备数据。。。。。");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            d.signal = true;
        }).start();
        // 第二个线程
        new Thread(() -> {
            while (!d.signal) {
                // 这里防止一直循环 稍微休眠
                try {
                    Thread.sleep(800);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("模拟代码执行。。。。");
        }).start();
    }
}

上面的方式通过while循环去阻塞,会非常的耗费资源,那么有没有更简单的方式呢?答案是有的

在Object对象中,有两个方法,wait()跟notify(),它们的作用就是用来阻塞线程跟唤醒线程

首先需要了解使用它们的条件:

  • 在同步代码块中使用
  • 使用的必须是同步代码块对象的wait()与notify()方法
public class Demo {
    public static void main(String[] args) {
        Demo d = new Demo();

        // 第一个线程
        new Thread(() -> {
            System.out.println("准备数据。。。。。");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("准备数据完成。。。");
            synchronized (d) {
                d.notify();
            }
        }).start();

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread() + "等待代码执行。。。");
                synchronized (d) {
                    try {
                        d.wait();   // wait会释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread() + "模拟代码执行。。。。");
            }).start();
        }
    }
}

关于wait与notify的特点

  • wait()在执行后会释放掉synchronized锁,因此使得上面的代码执行起来没有问题
  • 执行notify()方法会加锁
  • notify()只会随机唤醒一个被等待的线程,如果需要全部唤醒,则必须执行notifyAll()方法

Condition条件锁

Condition接口中的await()跟signal()方法的作用与wait()跟notify()的一致

Condition使用实例:

public class ConditionTest {
    private Lock lock = new ReentrantLock();
    private Condition a = lock.newCondition();
    private Condition b = lock.newCondition();

    public void a() {
        while (true) {
            lock.lock();
            try {
                a.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("a");
            b.signal();
            lock.unlock();
        }
    }

    public void b() {
        while (true) {
            lock.lock();
            a.signal();
            System.out.println("b");
            try {
                b.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ConditionTest ct = new ConditionTest();
        // 要求:a b c方法有序执行
        new Thread(ct::a).start();

        new Thread(ct::b).start();
    }
}

通过上面的实例,可以知道await()跟signal()也是需要使用锁的。

以上是关于线程通信的主要内容,如果未能解决你的问题,请参考以下文章

Motan在服务provider端用于处理request的线程池

在tablayout片段之间进行通信[重复]

与另一个片段通信的片段接口

无法通过接口获取与片段通信的活动

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

完成端口线程的 OutOfMemoryException