线程的通信:其实就是方法的使用
比如两个线程都来操作共享数据,他们之间如果又有某种交流就可以看成是线程的通信
比如:打印1到100的数字,要求两个线程交替打印,并且规定被某个线程打印过的,另一个线程就不能再打了。而且要求你打一下,我打一下,这就是一种交流,就叫线程的通信
涉及到的线程通信的三个方法:wait(),notify(),notifyAll()
- wait():使得调用它的线程进入阻塞状态
- notify():一个线程调用notify可以唤醒被wait的另一个线程。如果有多个线程wait了,调用这个方法唤醒哪个线程就看优先级谁高。即只能唤醒1个
- notifyAll():假设有多个线程,除了一个线程其他都wait了,这个线程调用notifyAll可以唤醒其他所有被wait的线程。即可以唤醒所有
说明:
- 1.使用前提:线程通信的三个方法只能出现在同步代码块或者同步方法中。不能用Lock的方式(Lock实现通信是采用其他方式)
- 2.wait(),notify(),notifyAll()前面都省略了this.,在下面的程序中指的就是n
- 3.wait(),notify(),notifyAll()的调用者必须是同步代码块或者同步方法中的同步监视器
- 4.这三个方法不是定义在Thread类当中的,是定义在Object类当中的(由同步监视器可以由任何对象充当,这三个方法调用者必须是同步代码块或者同步方法中的同步监视器也可以反映出这些方法是定义在Object类当中的)
例子: 使用两个线程打印 [1,100],要求线程1, 线程2 交替进行打印
- [1,100]为两个线程的共享数据
- 只要操作共享数据就会有安全问题
- 加sleep只是为了出现安全问题,但执行同步操作之后是不会出线程安全问题的的,所以没有必要加sleep。如果想让程序打印慢一点可以加sleep
- 当一个线程打印完之后为了实现通信,可以进行阻塞(使用wait()方法),这样在这段时间内执行别的线程,实现交替打印
package test0;
public class ThreadDemo {
public static void main(String[] args) {
Number n=new Number();
Thread t1=new Thread(n);//new出线程
Thread t2=new Thread(n);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
/*
比如一开始的时候线程1进来,这个时候notify()没什么意义,因为没有wait的线程,只是执行了一下这个方法而已。线程1wait之后
线程2进来,就用notify唤醒线程1,此时锁是2拿着的,1唤醒对2没影响。wait还有一个效果:一旦执行wait会释放锁,线程2wait之后,1拿到了锁
1就可以进来了。这里wait和sleep不一样。虽然sleep阻塞了线程,但锁依然不会被释放
*/
class Number implements Runnable{
private int number=1;
//private Object obj=new Object();
@Override
public void run() {
while(true){
synchronized(this){//注意:这个this一定要和调用notify的this是一致的,否则抛异常,所以这里千万不能用obj,除非下面写成obj.notify();obj.wait();
notify();//这里写notifyAll()也一样
if(number<=100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":,数字为:" + number);
number++;
try {
wait();//当一个线程处于运行状态时,调用wait就进入阻塞状态了,使用notify()或者notifyAll()才能恢复到就绪状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
}
}
}
sleep()和wait()的异同?
同: 一旦执行可以让当前线程进入阻塞状态
异:
1.sleep()是在Thread类中声明的,wait()是在Object类中声明的
2.调用的要求不同:sleep可以在任何需要的场景下调用,wait必须用同步监视器调用,即必须使用在同步代码块或者同步方法中
3.如果两个方法都使用在同步代码块或者同步方法中,sleep不会释放同步监视器,而wait会