多线程之线程间通信
什么是等待通知机制
在单线程中,要执行的操作需要满足一定条件才能执行,可以把这个操作放在if语句块中。
在多线程编程中,可能A线程的条件没有满足只是暂时的,稍后其他的线程B可能会更新条件使得A线程的条件得以满足,可以将A线程暂停,直到它的条件得到满足之后再将A线程唤醒
Atomic{
 while(条件不成立)
 {
 等待
 }
 条件满足后,当前线程被唤醒
}
等待通知机制的实现
object类中的Wait方法可以使当前线程的代码暂停执行,直到接到通知或者被中断为止
注意:
(1)wait方法只能再同步代码块中由锁对象调用
(2)调用wait方法,当前线程会释放锁
public class Text16_5 {
    public static void main(String[] args) throws InterruptedException {
        String text="hello";
        System.out.println("同步前代码块");
        synchronized (text)
        {
            System.out.println("同步代码块开始");
            text.wait();
            System.out.println("同步代码块结束");
        }
        System.out.println("全部结束");
    }
}

因为调用了锁对象的wait方法,会释放锁对象,处于等待的状态,没有被唤醒就会一直等待下去。
object类的notify方法可以唤醒线程,该方法也必须同步在代码块中,由锁对象调用,没有使用锁对象调用wait/notify会报出IIegalMonuitorStateExeption异常,如果由多个等待的线程,notify方法只能唤醒其中的一个,在同步代码块中调用notify方法后,并不会立即释放锁对象,需要等当前同步代码块执行完后才会释放锁对象,一般将notify放在同步代码块最后。
synchronized(锁对象)
{
  //执行修改保护条件的代码
  //唤醒其他线程
  锁对象.notify();
}
public class TextNotify {
    public static void main(String[] args) throws InterruptedException {
        String text="hello";
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (text)
                {
                    System.out.println("同步代码块开始");
                    try {
                        text.wait();//线程等待 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("同步代码块结束");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (text)
                {
                    System.out.println("线程开始唤醒");
                    text.notify();
                    System.out.println("线程结束唤醒");
                }
            }
        });
        t1.start();//开启t1线程 t1等待
        Thread.sleep(3000);//睡眠3秒 确保t1处于等待状态
        t2.start();//唤醒t1线程
    }
}

notify不会立即释放锁对象
案例:
import java.util.ArrayList;
import java.util.List;
public class NotifyText2 {
    public static void main(String[] args) throws InterruptedException {
        List<String> strings=new ArrayList<>();
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (strings)
                {
                    System.out.println("线程1开始等待");
                    try {
                        strings.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1被唤醒");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
               synchronized (strings)
               {
                   for (int i = 0; i <10 ; i++) {
                       strings.add("data"+i);
                       System.out.println("线程2添加了"+(i+1));
                       if(strings.size()==5)
                       {
                           strings.notify();
                           System.out.println("线程2被唤醒");
                       }
                   }
               }
            }
        });
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}
线程2的代码还没有执行完毕,锁没有立即释放依然在执行,需要等到所有代码块全部执行完毕才释放

interrupt会中断线程的等待
public class InterruptText {
    private static  final String name=new String();
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (name)
                {
                    try {
                        System.out.println("同步代码块开始");
                        name.wait();
                        System.out.println("同步代码块结束");
                    } catch (InterruptedException e) {
                        System.out.println("wait被中断"+e);
                    }
                }
            }
        });
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();
    }
}
原来锁对象需要执行完同步代码块才能释放锁对象,在执行过程如果遇到异常也会导致线程终止,释放锁对象。调用wait方法也会释放锁对象。

notify与notifyAll的区别
notify一次只能唤醒一个,如果有多个线程都在等待,只能随机唤醒其中的一个,想要唤醒所有等待线程需要调用notifyAll。
public class InterruptText {
    private static  final String name=new String();
    public static void main(String[] args) throws InterruptedException {
        String str=new String();
        NotifyAll notifyAll=new NotifyAll(str);
        NotifyAll notifyAl2=new NotifyAll(str);
        NotifyAll notifyAll3=new NotifyAll(str);
        notifyAll.setName("线程一");
        notifyAl2.setName("线程二");
        notifyAll3.setName("线程三");
        notifyAll.start();
        notifyAl2.start();
        notifyAll3.start();
        Thread.sleep(2000);//休眠两秒
        synchronized (str)
        {
            //str.notify();只能随机唤醒一个
            str.notifyAll();//唤醒全部线程
        }
    };
     static class NotifyAll extends Thread
    {
        private    String name;
        private  NotifyAll(String name)
        {
            this.name=name;
        }
                @Override
                public void run() {
                    synchronized (name)
                    {
                        try {
                            System.out.println(Thread.currentThread().getName()+"同步代码块开始");
                            name.wait();
                            System.out.println(Thread.currentThread().getName()+"同步代码块结束");
                        } catch (InterruptedException e) {
                            System.out.println("wait被中断"+e);
                        }
                    }
                }
    }
}

如果只调用一次notify()之恶能唤醒其中的一个线程,其他等待线程依然处于等待状态,就错过了通知信号,这种现象称之为信号丢失。
wait(Long)的使用
带有参数的Wait(Long)方法,在指定时间内没有操作会被自动唤醒

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号