多线程系列六-线程间通信 wait和notify、threadlocal等

线程通信

线程是系统的个体,线程想要构成一个整体,就需要线程间通信。使用wait和notify可以实现线程间通信。

wait和notify

wait和notify是Object的方法。他们都涉及到锁相关操作
- wait:等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。所以只能在同步方法或者同步块中调用wait方法

调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。

  • notify:唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。同样,也只能在同步方法或者同步块中调用notify方法

    调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。

  • notifyAll:唤醒所有等待的线程,注意唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。

总之:
1. wait使线程等待(释放锁给调用notify的线程,等待锁),notify使停止线程运行。
2. 两者都要在同步方法中运行。
3. notify方法执行后不会立即释放锁。只是让线程进入就绪状态。等notify所在的同步方法执行完之后才释放锁。
4. notify一次只能随机唤醒一个线程。当有多个需要唤醒时,可调用notifyAll
5. wait(long)可以自动唤醒。

示例1 不在同步方法中调用wait

public class WaitTest {
    public static void main(String[] args){
        String lock=new String();
        try {
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
输出异常:
Exception in thread "main" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.thread3.communicate.WaitTest.main(WaitTest.java:7)

改为在同步方法中调用:

public class WaitTest {
    public static void main(String[] args) {
        String lock = new String();
        try {
            synchronized (lock) {
                lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

示例2 wait和notify

class MyThreadA extends Thread {
    private Object lock;

    public MyThreadA(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            System.out.println("ThreadA 1");
            synchronized (lock) {
                System.out.println("ThreadA 2");//打印这个之后会进行等待
                lock.wait();
                System.out.println("ThreadA 3");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MyThreadB extends Thread {
    private Object lock;

    public MyThreadB(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {

        System.out.println("ThreadB 1");
        synchronized (lock) {
            System.out.println("ThreadB 2");
            lock.notify();
            System.out.println("ThreadB 3");
        }

    }
}

public class WaitNotifyTest {

    public static void main(String[] args) throws InterruptedException {
        String lock = new String();
      MyThreadA threadA=new MyThreadA(lock);
      MyThreadB threadB=new MyThreadB(lock);
      threadA.start();
      Thread.sleep(2000);
      threadB.start();
    }
}
输出结果:

ThreadA 1
ThreadA 2
ThreadB 1
ThreadB 2
ThreadB 3 //这个比下面先输出,可以看出调用notify不会立即释放锁,让线程A立即执行。
ThreadA 3

interrupt遇到wait方法

当线程处于wait状态时,调用线程的interrupt,会跑出InterruptedException异常。

class MyThreadAA extends Thread {
    private Object lock;

    public MyThreadAA(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            System.out.println("MyThreadAA 1");
            synchronized (lock) {
                System.out.println("MyThreadAA 2");//打印这个之后会进行等待
                lock.wait();
                System.out.println("MyThreadAA 3");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}



public class WaitInterruptExpTest {

    public static void main(String[] args) throws InterruptedException {
        String lock = new String();
        MyThreadAA threadA=new MyThreadAA(lock);

        threadA.start();
        Thread.sleep(2000);

        threadA.interrupt();
    }
}
输出:
MyThreadAA 1
MyThreadAA 2
java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.thread3.communicate.MyThreadAA.run(WaitInterruptExpTest.java:16)

应用场景 生产者/消费者

线程间通信还可以用管道:pipeStream

你可能感兴趣的:(java-多线程并发,多线程,通信)