Java并发编程原理与实战二十一:线程通信wait&notify&join

Posted 屌丝码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发编程原理与实战二十一:线程通信wait&notify&join相关的知识,希望对你有一定的参考价值。

wait和notify

wait和notify可以实现线程之间的通信,当一个线程执行不满足条件时可以调用wait方法将线程置为等待状态,当另一个线程执行到等待线程可以执行的条件时,调用notify可以唤醒等待的线程。需要强调的是,在调用wait和notify时需要先获取锁,否则会抛出IllegalMonitorException异常。notify方法随机从等待的线程中唤醒一个线程执行,notifyAll方法唤醒所有的等待线程,这些线程竞争时间片。下面是一个使用wait和notify的例子:当写线程将signal唤醒标志为1时,读线程才可以读。

public class Demo {

    private volatile int signal;

    public synchronized int getSignal() {
        System.out.println(Thread.currentThread().getName() + " 进入同步方法了");
        if (signal != 1) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return signal;
    }

    public synchronized void setSignal(int signal) {
        System.out.println(Thread.currentThread().getName() + " 唤醒了");
        this.signal = signal;
        notifyAll();
    }

    public static void main(String[] args) {
        Demo demo = new Demo();
        TaskOne taskOne = new TaskOne(demo);

        TaskTwo taskTwo = new TaskTwo(demo);

        // 开启读线程

        new Thread(taskOne).start();
        new Thread(taskOne).start();
        new Thread(taskOne).start();
        new Thread(taskOne).start();

 

        // 开启写线程

        new Thread(taskTwo).start();
    }

}

public class TaskOne implements Runnable {

    private Demo demo;

    public TaskOne(Demo demo) {
        this.demo = demo;
    }

    @Override
    public void run() {
        demo.getSignal();
    }
}

public class TaskTwo implements Runnable {

    private Demo demo;

    public TaskTwo(Demo demo) {
        this.demo = demo;
    }

    @Override
    public void run() {
        demo.setSignal(1);
    }

}

2.用wait和notify实现生产者和消费者

public class Table {

    private int count;

    private static final int MAX_COUNT = 10;

    public synchronized void push() {
        while (count >= MAX_COUNT) {
            try {
                System.out.println(Thread.currentThread().getName() + "桌子已放满,生产者停止生产");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count++;

        System.out.println(Thread.currentThread().getName() + "桌子上当前产品数量: "+ count);

        // 桌上一有产品就唤醒消费者

        notifyAll();
    }

    public synchronized void take() {
        while (count <= 0) {
            try {
                System.out.println(Thread.currentThread().getName() + "桌子已空,消费者停止消费");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;

        System.out.println(Thread.currentThread().getName() + "桌上剩余产品: " + count);

        // 当桌子上的产品被消费完后唤醒生产者

        notifyAll();
    }

}

public class Productor implements Runnable {

    private Table table;

    public Productor(Table table) {
        this.table = table;
    }

    @Override
    public void run() {
        while (true) {
            table.push();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

public class Consumer implements Runnable {

    private Table table;

    public Consumer(Table table) {
        this.table = table;
    }

    @Override
    public void run() {
        while (true) {
            table.take();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

public class Demo {
    public static void main(String[] args) {
        Table table = new Table();
        Productor productor = new Productor(table);
        Consumer consumer = new Consumer(table);

        new Thread(productor).start();
        new Thread(productor).start();
        new Thread(productor).start();
        new Thread(productor).start();

        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
    }
}

2.join

调用join方法的线程会加塞到其他线程之前执行,被加塞的线程在调用join方法的线程执行完后才接着执行。

public class JoinDemo {

    public void a(Thread joinThread) {
        System.out.println("线程a开始执行...");
        joinThread.start();
        try {
            // 当前线程阻塞直到joinThread执行完毕
            joinThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程a执行结束...");
    }

    public void b() {
        System.out.println("加塞线程开始执行...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("加塞线程执行结束...");
    }

    public static void main(String[] args) {
        final JoinDemo demo = new JoinDemo();
        final Thread joinThread = new Thread() {
            @Override
            public void run() {
                demo.b();
            }
        };

        new Thread() {
            @Override
            public void run() {
                demo.a(joinThread);
            }
        }.start();
    }
}

 

参考资料:

《java并发编程实战》龙果学院

以上是关于Java并发编程原理与实战二十一:线程通信wait&notify&join的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理

Java并发编程原理与实战二十:线程安全性问题简单总结

Java并发编程原理与实战二十九:Exchanger

Java并发编程原理与实战四十一:重排序 和 happens-before

Python从入门到精通(二十一)Python并发编程互斥锁的运用以及线程通信

转:Java并发编程之十一:线程间通信中notify通知的遗漏(含代码)