资讯专栏INFORMATION COLUMN

java多线程(7)wait()、notify()和notityALL()

LiuRhoRamen / 699人阅读

摘要:已经在上面有提到过,和的作用是唤醒正在的线程,是随机唤醒线程中的一个,则是唤醒全部。释放和不释放锁在多线程的操作中,锁的释放与否是必须要清楚的,是会释放锁,而则不会。

wait

wait方法是Object中的方法,这个方法的功能特性:
1).执行wait方法的前提是当前线程已经获取到对象的锁,也就是wait方法必须在synchronized修饰的代码块或者方法中使用。
2).执行wait之后,会失去锁的所有权
3).wait方法执行后会一直等待,直到被调用notify()、notifyAll()或者所在线程被中断。
4).被调用notify()或者notifyAll()后,线程还是会等待,直到拥有锁的所有权,才会继续往下执行。
下面举个例子:

    public static void main(String[] args) throws InterruptedException {
        Object lock1 = new Object();
        Thread t1 = new Thread(new Test().new Tt1(lock1));
        Thread t2 = new Thread(new Test().new Tt2(lock1));
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
    
    
    class Tt1 implements Runnable{

        private Object lock1;
        
        public Tt1(Object lock1) {
            this.lock1 = lock1;
        }

        @Override
        public void run() {
            try {
                System.out.println(this.getClass()+"-------1");
                synchronized (lock1) {
                    Thread.sleep(2000);
                    System.out.println("waiting start");
                    lock1.wait();
                }
                System.out.println("waiting end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Tt2 implements Runnable{

        private Object lock1;
        
        public Tt2(Object lock1) {
            this.lock1 = lock1;
        }

        @Override
        public void run() {
            System.out.println(this.getClass()+"-------1");
            synchronized (lock1) {
                try {
                    System.out.println(this.getClass()+"-------2");
                    lock1.notify();
                    Thread.sleep(1000);
                    System.out.println(this.getClass()+"-------3");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            
        }
    }

执行结果:

class Test$Tt1-------1
class Test$Tt2-------1
waiting start
class Test$Tt2-------2
class Test$Tt2-------3
waiting end

分析一下:
第1、2行:t1和t2启动,t1先获取到锁所以t2一直被阻塞住
第3、4行:t1中执行了wait,锁被释放,所以t2继续执行下去。
第5、6行:t2中调用了notify()但是t1没有马上执行,因为锁现在是被t2拥有,等t2执行完成释放锁后,t1继续执行。

notify、notifyAll

notify已经在上面有提到过,notify和notifyAll 的作用是唤醒正在wait的线程,notify是随机唤醒wait线程中的一个,notifyAll 则是唤醒全部。

1).执行notify、notifyAll 方法的前提是当前线程已经获取到对象的锁,也就是必须在synchronized修饰的代码块或者方法中使用。这个和wait是一样的。
2).被调用notify()或者notifyAll()后,线程还是会等待,直到拥有锁的所有权,才会继续往下执行。
3)notify、notifyAll不会释放锁,这个与wait不同。

释放和不释放锁

在多线程的操作中,锁的释放与否是必须要清楚的,wait是会释放锁,而notify(notifyAll)则不会。先举个wait的例子:

    public static void main(String[] args) throws InterruptedException {
        Object lock1 = new Object();
        Thread t1 = new Thread(new Test().new Tt1(lock1));
        Thread t2 = new Thread(new Test().new Tt2(lock1));
        t1.start();
        Thread.sleep(100);
        t2.start();
    }
    
    class Tt1 implements Runnable{
        private Object lock1;
        
        public Tt1(Object lock1) {
            this.lock1 = lock1;
        }

        @Override
        public void run() {
            try {
                synchronized (lock1) {
                    System.out.println(Thread.currentThread().getName()+"---start");
                    lock1.wait();
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()+"---end");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Tt2 implements Runnable{

        private Object lock1;
        
        public Tt2(Object lock1) {
            this.lock1 = lock1;
        }

        @Override
        public void run() {
            synchronized (lock1) {
                try {
                    System.out.println(Thread.currentThread().getName()+"---start");
                    System.out.println(Thread.currentThread().getName()+"---end");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            
        }
    }

执行结果:

Thread-0---start
Thread-1---start
Thread-1---end

Thread-0执行wait后马上释放了锁,所以Thread-1很快接着就执行。

再来notify的例子,其实就是把上一个例子wait()改成nofity():

    public static void main(String[] args) throws InterruptedException {
        Object lock1 = new Object();
        Thread t1 = new Thread(new Test().new Tt1(lock1));
        Thread t2 = new Thread(new Test().new Tt2(lock1));
        t1.start();
        Thread.sleep(100);
        t2.start();
    }
    
    class Tt1 implements Runnable{
        private Object lock1;
        
        public Tt1(Object lock1) {
            this.lock1 = lock1;
        }

        @Override
        public void run() {
            try {
                synchronized (lock1) {
                    System.out.println(Thread.currentThread().getName()+"---start");
                    lock1.notify();
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()+"---end");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Tt2 implements Runnable{

        private Object lock1;
        
        public Tt2(Object lock1) {
            this.lock1 = lock1;
        }

        @Override
        public void run() {
            synchronized (lock1) {
                try {
                    System.out.println(Thread.currentThread().getName()+"---start");
                    System.out.println(Thread.currentThread().getName()+"---end");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            
        }
    }

执行结果:

Thread-0---start
Thread-0---end
Thread-1---start
Thread-1---end

可见Thread-0在执行nofity后并没有释放锁,而是等待代码块执行完之后才释放锁,Thread-1才能继续执行。

必须先获取锁

无论是notify还是wait都是要先获取锁,既必须在synchronized内使用,举个反例:

public static void main(String[] args) throws InterruptedException {
            Object lock1 = new Object();
            Thread t1 = new Thread(new Test().new Tt1(lock1));
            t1.run();
        }
        
        class Tt1 implements Runnable{
            private Object lock1;
            
            public Tt1(Object lock1) {
                this.lock1 = lock1;
            }
    
            @Override
            public void run() {
                try {
                    lock1.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

执行结果:

Exception in thread "main" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at Test$Tt1.run(Test.java:24)
    at java.lang.Thread.run(Thread.java:748)
    at Test.main(Test.java:11)
wait()遇到interrupt()

之前说道interrupt(),并不会直接中断线程,而是会给线程一个中断标志,而且包括sleep、wait、join会抛出InterruptedException。

    public static void main(String[] args) throws InterruptedException {
            Object lock1 = new Object();
            Thread t1 = new Thread(new Test().new Tt1(lock1));
            t1.start();
            Thread.sleep(100);
            t1.interrupt();
        }
        
        class Tt1 implements Runnable{
            private Object lock1;
            
            public Tt1(Object lock1) {
                this.lock1 = lock1;
            }
    
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        System.out.println(Thread.currentThread().getName()+"---start");
                        lock1.wait();
                        System.out.println(Thread.currentThread().getName()+"---end");
                    }catch (InterruptedException e) {
                        System.out.println("线程被中断了");;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }

执行结果:

Thread-0---start
线程被中断了
notifyAll和nofity

notifyAll和nofity唯一的不同就是,可以唤醒全部和唤醒一个, 先举个nofity的例子

        public static void main(String[] args) throws InterruptedException {
            Object lock1 = new Object();
            Thread t1 = new Thread(new Test().new Tt1(lock1));
            Thread t2 = new Thread(new Test().new Tt1(lock1));
            Thread t3 = new Thread(new Test().new Tt2(lock1));
            t1.start();
            Thread.sleep(100);
            t2.start();
            Thread.sleep(100);
            t3.start();
        }
        
        class Tt1 implements Runnable{
            private Object lock1;
            
            public Tt1(Object lock1) {
                this.lock1 = lock1;
            }
    
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        System.out.println(Thread.currentThread().getName()+"---start");
                        System.out.println(Thread.currentThread().getName()+"---wait");
                        lock1.wait();
                        System.out.println(Thread.currentThread().getName()+"---end");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
        class Tt2 implements Runnable{
    
            private Object lock1;
            
            public Tt2(Object lock1) {
                this.lock1 = lock1;
            }
    
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        System.out.println(Thread.currentThread().getName()+"---start");
                        System.out.println(Thread.currentThread().getName()+"---notify");
                        lock1.notify();
                        System.out.println(Thread.currentThread().getName()+"---end");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                
            }
        }

执行结果:

Thread-0---start
Thread-0---wait
Thread-1---start
Thread-1---wait
Thread-2---start
Thread-2---notify
Thread-2---end
Thread-0---end

Thread-0和Thread-1在wait,Thread-2执行了notify,但只有Thread-0被唤醒,重新开始执行,Thread-1还在wait。

再来看看nofityAll:

        public static void main(String[] args) throws InterruptedException {
            Object lock1 = new Object();
            Thread t1 = new Thread(new Test().new Tt1(lock1));
            Thread t2 = new Thread(new Test().new Tt1(lock1));
            Thread t3 = new Thread(new Test().new Tt2(lock1));
            t1.start();
            Thread.sleep(100);
            t2.start();
            Thread.sleep(100);
            t3.start();
        }
        
        class Tt1 implements Runnable{
            private Object lock1;
            
            public Tt1(Object lock1) {
                this.lock1 = lock1;
            }
    
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        System.out.println(Thread.currentThread().getName()+"---start");
                        System.out.println(Thread.currentThread().getName()+"---wait");
                        lock1.wait();
                        System.out.println(Thread.currentThread().getName()+"---end");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        
        class Tt2 implements Runnable{
    
            private Object lock1;
            
            public Tt2(Object lock1) {
                this.lock1 = lock1;
            }
    
            @Override
            public void run() {
                synchronized (lock1) {
                    try {
                        System.out.println(Thread.currentThread().getName()+"---start");
                        System.out.println(Thread.currentThread().getName()+"---notifyAll");
                        lock1.notifyAll();
                        System.out.println(Thread.currentThread().getName()+"---end");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                
            }
        }

执行结果:

Thread-0---start
Thread-0---wait
Thread-1---start
Thread-1---wait
Thread-2---start
Thread-2---notifyAll
Thread-2---end
Thread-1---end
Thread-0---end

Thread-2执行了notifyAll后,Thread-1和Thread-0都被唤醒。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76374.html

相关文章

  • Java 线程编程之:notify wait 用法

    摘要:和简介和均为的方法暂停一个线程唤醒一个线程从以上的定义中,我们可以了解到以下事实想要使用这两个方法,我们需要先有一个对象。在中任何一个时刻,对象的控制权只能被一个线程拥有。若有多个线程处于此控制权下的状态,只有一个会被唤醒。 最近看帖子,发现一道面试题: 启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4...

    eccozhou 评论0 收藏0
  • JAVA线程间通信简介

    摘要:线程通信的目标是使线程间能够互相发送信号。但是,这个标志已经被第一个唤醒的线程清除了,所以其余醒来的线程将回到等待状态,直到下次信号到来。如果方法调用,而非,所有等待线程都会被唤醒并依次检查信号值。 线程通信的目标是使线程间能够互相发送信号。另一方面,线程通信使线程能够等待其他线程的信号。 showImg(http://segmentfault.com/img/bVbPLD); 例...

    CHENGKANG 评论0 收藏0
  • Java线程学习(四)等待/通知(wait/notify)机制

    摘要:运行可运行状态的线程获得了时间片,执行程序代码。阻塞的情况分三种一等待阻塞运行的线程执行方法,会把该线程放入等待队列中。死亡线程方法执行结束,或者因异常退出了方法,则该线程结束生命周期。死亡的线程不可再次复生。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键...

    PiscesYE 评论0 收藏0
  • bat等大公司常考java线程面试题

    摘要:典型地,和被用在等待另一个线程产生的结果的情形测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用使其恢复。使当前线程放弃当前已经分得的时间,但不使当前线程阻塞,即线程仍处于可执行状态,随时可能再次分得时间。 1、说说进程,线程,协程之间的区别 简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程.进程在执行过程中拥有独立的内存单元...

    Charlie_Jade 评论0 收藏0
  • 线程编程:wait, notify, join, yield都有啥用?

    摘要:通知任一一个进入等待状态的线程,通知所有让调用线程阻塞在这个方法上,直到的线程完全执行完毕,调用线程才会继续执行。通知调度器,主动让出对的占用。 多线程在开发知识中是一个很重要的部分,然而实际生产中却很少遇到真正需要自己去处理多线程编程里的那些复杂细节和问题,因为很多时候,都有一套架构或者一些框架帮大部分业务程序员隐藏了多线程的细节,大多时候只需要简单的实现各种业务逻辑即可。 今天来理...

    lovXin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<