Java线程学习笔记(8)—— 线程间通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012292754/article/details/88751061

1 线程间通信

多个线程并发执行时, 在默认情况下CPU是随机切换线程的,如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印

1.1 如何通信

  • 如果希望线程等待, 就调用wait()
  • 如果希望唤醒等待的线程, 就调用notify();
  • notify是随机唤醒一个线程
  • notifyAll是唤醒所有线程
  • 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
  • 如果方法中没有同步锁,会有异常IllegalMonitorStateException

2 两个线程之间的通信

package threadtest;

public class Demo12 {

    public static void main(String[] args) {
        MyTask task = new MyTask();


        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        task.task1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        task.task2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

    }
}

class MyTask {

    int flag = 1; // 执行任务1

    public synchronized void task1() throws InterruptedException {
        if (flag != 1) {
            this.wait(); // 当前线程等待
        }
        System.out.println("1.银行信用卡自动还款任务....");
        flag = 2;
        this.notify(); // 唤醒其他线程
    }

    public synchronized void task2() throws InterruptedException {
        if (flag != 2) {
            this.wait();
        }
        System.out.println("2.自动利息结算任务。。。");

        flag = 1;
        this.notify();

    }
}

3 三个线程的通信

package threadtest;

public class Demo12 {

    public static void main(String[] args) {
        MyTask task = new MyTask();


        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        task.task1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        task.task2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        task.task3();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

    }
}

class MyTask {

    int flag = 1; // 执行任务1

    public synchronized void task1() throws InterruptedException {
        if (flag != 1) {
            this.wait(); // 当前线程等待
        }
        System.out.println("1.银行信用卡自动还款任务....");
        flag = 2;
       // this.notify(); // 唤醒随机线程
        this.notifyAll();
    }

    public synchronized void task2() throws InterruptedException {
        if (flag != 2) {
            this.wait();
        }
        System.out.println("2.自动利息结算任务。。。");

        flag = 3;
        // this.notify(); // 唤醒随机线程
        this.notifyAll();

    }

    public synchronized void task3() throws InterruptedException {
        if (flag != 3) {
            this.wait();
        }
        System.out.println("3.短信提醒。。。");

        flag = 1;
        // this.notify(); // 唤醒随机线程
        this.notifyAll();

    }
}

3.1 多线程通信问题

  • JDK5之前无法唤醒指定的一个线程;
  • 如果多个线程之间通信,需要使用 notifyAll() 通知所有的线程,用 while 来反复判断条件;

4 线程通信的注意问题

  1. 在同步代码块中,用哪个对象锁,就用哪个对象锁调用 wait 方法

4.1 为什么 wait 方法和 notify 方法定义在 Object 类中?

  • 因为锁对象可以是任意的,Object 是所有的类的基类;

4.2 sleep 方法和 wait 方法的区别?

  1. sleep 方法必须传入参数,参数就是时间,时间到了自动醒来;
  2. wait 方法可以传入参数,可以不传入参数。传入参数就是在参数的时间结束后等待,不传入参数就是直接等待;
  3. sleep 方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁;
  4. wait 方法在同步函数或者同步代码块中,释放锁

猜你喜欢

转载自blog.csdn.net/u012292754/article/details/88751061