同步机制中notify()与wait()--实现A,B,C循环打印

来源:互联网 发布:c语言考题 编辑:程序博客网 时间:2024/05/25 08:13

关于同步与异步机制,听过很多通俗的解释。

日常生活中其实也有很多这样的例子,比如吃饭的时候

同步:就是你通知我去吃饭,我听到了就和你一起去,如果我没有回应,你就会一直喊,直到我有反映了为止。

异步:你通知我一声后,不管我有没有回应,你自己就去吃饭去了。

在通讯当中:

同步:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。 

异步:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

java在实现同步机制的过程中,主要用到了两种方法,一种是同步方法,一种是同步代码块。两种都用到了synchronized关键字。

同步方法:

public void sychronized study() {        System.out.println("studying");}
同步代码块:

(sychronized){     ......}
说到这里,下面说一下在同步代码块中使用notify(),以及wait()来实现一个经典的线程打印问题--利用三个线程A,B,C分别各自循环打印A,B,C.

关于notify()以及wait(),这里叙述一下。


我们可以看到,wait()与notify()同属于object类的方法,由于object被所有类所继承,所以这两个方法也会被所有类所继承。而且,我们看源码,关于两个方法

public final native void notify();
public final void wait() throws InterruptedException {        wait(0);    }
两个方法都有final修饰,则在子类中不能够被重写。

wait 方法:
使当前线程一直处于等待的状态,直到另一个线程在调用了notify()或者notifyAll()方法。

当前线程拥有当前对象的锁,即wait()方法应该在sychronized{}方法或者代码块中。调用wait()方法后,释放对当前对象锁的拥有。

notify()方法:

唤醒处于等待状态的线程,这里应该注意是,如果有多个线程处于等待的状态,那么调用一次notify()方法后,具体释放的是哪一个线程是不确定的,执行的过程是java虚拟机来实现的。

跟wait方法一样,notify也是必须放在synchronized方法或synchronized块中。

关于wait()与notify()方法,利用三个线程循环打印A,B,C是很具有代表性的。

public class MyThread {public static void main(String[] args) throws Exception {Object A = new Object();Object B = new Object();Object C = new Object();Thread t1 = new Thread(new Print(A, B), "A");Thread t2 = new Thread(new Print(B, C), "B");Thread t3 = new Thread(new Print(C, A), "C");                                //Thread.sleep(1)为了让打印的时候依次执行t1.start();Thread.sleep(1);t2.start();Thread.sleep(1);t3.start();}}class Print implements Runnable {private Object self;private Object next;public Print(Object self, Object next) throws InterruptedException {this.self = self;this.next = next;}public void run() {for (int i = 0; i < 10; i++) {synchronized (self) {synchronized (next) {System.out.println(Thread.currentThread().getName());next.notify();}try {if (i == 9) {return; // 当i == 9 即最后一次循环, 将直接退出 不再进行等待}self.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}
打印的结果为ABCABCABCABCABCABCABCABCABCABC(当然,这里未显示换行符)

现在简单的看一下程序执行的过程。

首先线程A(这里为线程的名字)调用start方法,在run方法中,self为A,next为B,打印一下Thread.CurrentThread.getName()为A.然后执行self.wait(),即此时A处于阻塞状态。然后线程B(线程的名字)进入run方法,self为B,next为C,然后先打印一下B,再执行next.notify()方法,此时把之前处于阻塞状态的线程A不再阻塞。当执行下面的self.wait的时候,此时线程B就处于阻塞状态了,而线程A,C处于就绪状态,等待处理机的调度。然后线程C进入run方法,self为C,next为A,打印一下C,next.notify使之前处于阻塞的B处于就绪状态,然后 C再进入等待的状态,依次下去。
















0 0