我先提出一个例子
A,B为一组,A走1米,然后 B走一米,总共100米(就是A,B轮流输出100个数)
其实把AB当做线程,这便是一个线程通信的例子。
wait(); 使执行的线程进行等待
notify(); 使停止的线程继续运行,
join(); 使所属线程正常执行run方法,而当前线程暂时阻塞,有排队的作用
notify与notifyAll的区别
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者,以判断程序是否可以继续往下执行。
线程通信主要靠的是这3个函数,但是本次例子中只使用了前2个函数,join将单独讲解。
先看看本次例子代码如何写的
public class C{ //记录距离
int i=100;
boolean flag = false; //两个线程,交替执行的一个标志
}
public class A implements Runnable{
private C c;
public A(C c) {
this.c=c;
}
@Override
public void run() {
while(c.i>0) {
synchronized (c) { //必须要用一把锁对象,这个对象是c
if(c.flag) {
try {
c.wait(); //操作wait()函数的必须和锁是同一个
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
c.i--;
System.out.println("A跑完了,还剩下"+c.i+"米");
c.flag=true;
c.notify();
}
}
}
}
}
public class B implements Runnable{
private C c;
public B(C c) {
this.c=c;
}
@Override
public void run() {
while(c.i>0) {
synchronized (c) {
if(!c.flag) {
try {
c.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
c.i--;
System.out.println("B跑完了,还剩下"+c.i+"米");
c.flag=false;
c.notify();
}
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
C c=new C();
A a=new A(c);
B b=new B(c);
Thread a1=new Thread(a);
Thread b1=new Thread(b);
a1.start();
b1.start();
}
}
首先我们通过锁(也必须有锁)保证了他们只有一个执行,然后通过一个执行一个停止的机制保证了他们的轮换。
这个问题其实在线程通信中属于基础但不简单的,明白了其中的原理,在去搞其他线程通信就会容易很多的。