java 多线程之间的通信

来源:互联网 发布:原油指数软件 编辑:程序博客网 时间:2024/05/01 10:39
在多线程的编码实现中,往往每个线程之间是相互协作实现的,或者说是有先后顺序的,多线程之间的通信能够避免对同一共享变量的争夺。

一、wait()和 notify()

1. wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。  当前的线程必须拥有当前对象的monitor,也即lock,就是锁。     线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。    要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。      一个小比较:  当线程调用了wait()方法时,它会释放掉对象的锁。    另一个会导致线程暂停的方法:Thread.sleep(),它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。2. notify()方法会唤醒一个等待当前对象的锁的线程。  如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)。  **被唤醒的线程是不能被执行的,需要等到当前线程放弃这个对象的锁。**  被唤醒的线程将和其他线程以通常的方式进行竞争,来获得对象的锁。也就是说,被唤醒的线程并没有什么优先权,也没有什么劣势,对象的下一个线程还是需要通过一般性的竞争。    和 wait()方法一样,notify方法调用必须放在synchronized方法或synchronized块中。
import java.util.ArrayList;import java.util.List;public class MyList {    private static List<String> list = new ArrayList<String>();    public static void add() {        list.add("anyString");    }    public static int size() {        return list.size();    }}public class ThreadA extends Thread {    private Object lock;    public ThreadA(Object lock) {        super();        this.lock = lock;    }    @Override    public void run() {        try {            synchronized (lock) {                if (MyList.size() != 5) {                    System.out.println("wait begin "                            + System.currentTimeMillis());                    lock.wait();                    System.out.println("wait end  "                            + System.currentTimeMillis());                }            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }}public class ThreadB extends Thread {    private Object lock;    public ThreadB(Object lock) {        super();        this.lock = lock;    }    @Override    public void run() {        try {            synchronized (lock) {                for (int i = 0; i < 10; i++) {                    MyList.add();                    if (MyList.size() == 5) {                        lock.notify();                        System.out.println("已经发出了通知");                    }                    System.out.println("添加了" + (i + 1) + "个元素!");                    Thread.sleep(1000);                }            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }}public class Run {    public static void main(String[] args) {        try {            Object lock = new Object();            ThreadA a = new ThreadA(lock);            a.start();            Thread.sleep(50);            ThreadB b = new ThreadB(lock);            b.start();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list 的size。A,B之间如何通信的呢?也就是说,线程A如何知道 list.size() 已经为5了呢?这里用到了Object类的 wait() 和 notify() 方法。当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。

二、synchronized 关键字

public class MyObject {    synchronized public void methodA() {        //do something....    }    synchronized public void methodB() {        //do some other thing    }}public class ThreadA extends Thread {    private MyObject object;//省略构造方法    @Override    public void run() {        super.run();        object.methodA();    }}public class ThreadB extends Thread {    private MyObject object;//省略构造方法    @Override    public void run() {        super.run();        object.methodB();    }}public class Run {    public static void main(String[] args) {        MyObject object = new MyObject();        //线程A与线程B 持有的是同一个对象:object        ThreadA a = new ThreadA(object);        ThreadB b = new ThreadB(object);        a.start();        b.start();    }}
由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了通信。这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。
0 0
原创粉丝点击