一,等待/通知机制 实现线程间的通信
举个例子:我们去饭店就餐,饭店上餐的时间不确定,如果我们一直去询问前台,是不是很烦,我么这时就处于等待(wait)状态,但是 饭店肯定会有人肯定会通知 (notify),那个桌的菜已经做好了,前台就会通知这桌的人,菜来了。
1,主要的方法wait() /notify() 这个两个方法时Object类本地方法 都要在同步方法中调用
1),wait() 使执行当前代码的线程进行等待,执行完毕后,线程就会释放锁,以便别的线程可以获得锁。
2),notify(),随机挑选一个处于wait()的线程,让他获得锁,但这个方法不会立即释放当前线程的对象锁,只有程序执行完毕后,才会释放锁。
3)sleep()方法,这个方法也是不是放锁的 ,那么别的线程要获取这个锁就会处于等待状态。
4),在调用wait()方法后,使线程处于wait状态,这时如果调用interrupt()就会出现InterrruptedException异常
5),notify()方法一次只会通知一个线程。notifyAll()通知所有的线程
二,使用等待/通知机制,实现生产者/消费者模式
/**
* 通知等待机制 实现消费者者/生产者模式
*/
public class PCDemo {
//消费品
public static class Data{
public static String value = " ";
}
//生产者
public static class Producer{
private String lock;
public Producer(String value){
this.lock = value;
}
public void setValue() throws Exception{
synchronized (lock){
if (!Data.value.equals(" ")){ //说明value没有被消费
lock.wait();
}else{
String s = System.currentTimeMillis()+" ";
System.out.println("设置的value = " + s+" 当前线程的Name = "+Thread.currentThread().getName());
Data.value = s;//生产数据
lock.notify();//通知等待的消费者去消费
}
}
}
}
//消费者
public static class Consumer{
private String lock;
public Consumer(String lock){
this.lock = lock;
}
public void getValue() throws Exception{
synchronized (lock){
if (Data.value.equals(" ")){ //说明生产者没有生产数据
lock.wait();//消费者等待
}else {
System.out.println("消费者获得的值 "+ Data.value+" 当前线程的Name = "+Thread.currentThread().getName());
Data.value = " ";//模拟把数据消费了
lock.notify();//通知生产者赶快生产数据 ,我已经消费完了
}
}
}
}
//生产者线程
public static class ProThread implements Runnable{
private Producer producer;
public ProThread(Producer p){
this.producer = p;
}
@Override
public void run() {
while (true){
try {
producer.setValue();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//消费者线程
public static class ConThread implements Runnable{
private Consumer consumer;
public ConThread(Consumer consumer){
this.consumer = consumer;
}
@Override
public void run() {
try {
while (true){
consumer.getValue();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception{
String lock = new String(" ");//使用同一个锁对象
Thread p = new Thread(new ProThread(new Producer(lock)));
Thread c = new Thread(new ConThread(new Consumer(lock)));
p.setName("Producer");
c.setName("Consumer");
p.start();
c.start();
}
}
运行部分截图
这时一个生产者,一个消费者的情况,两个线程交替执行。
若果有多个消费者,多个生产者,则有可能产生“假死”现象,就是所有的线程都处于waitting,因为notify()方法一次只能使一个处于waitting状态的线程掉起来。解决办法使用notifiyAll()方法即可。
三,join():等待线程对象销毁,一个主线程要等待子线程结束在自行结束。
1,join()内部其实使用的是wait(),
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
join()方法具有使线程排队执行的作用,类似与同步的效果,但和synchroized的原理不同,后者使用 “对象监视器”原理