zoukankan      html  css  js  c++  java
  • synchronized块中的wait()、nofity()、nofityAll()方法

    前言

      在Java并发编程实战,会经常遇到多个线程访问同一个资源的情况,这个时候就需要维护数据的一致性,否则会出现各种数据错误,其中一种同步方式就是利用Synchronized关键字执行锁机制,锁机制是先给共享资源上锁,只有拿到锁的线程才可以访问共享资源,其他线程进入等待状态。下面将以实例代码讲解一下

    一、wait()、nofity()、nofityAll()讲解

      示例代码

    package thread;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    
    /**
     * Created by StoneGeek on 2018/5/19.
     * 博客地址:http://www.cnblogs.com/sxkgeek
     * 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。
     * 当线程执行notify()/notifyAll()方法时,会唤醒一个处于等待状态该对象锁的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁
     * 个人认为synachronized(){}执行完后会释放锁
     */
    public class WaitNotify {
        static boolean flag = true;
        static Object lock = new Object();
    
        public static void main(String[] args) throws Exception {
            Thread waitThread = new Thread(new Wait(), "WaitThread");
            waitThread.start();
            TimeUnit.SECONDS.sleep(1);
            Thread notifyThread = new Thread(new Notify(), "NotifyThread");
            notifyThread.start();
        }
    
        static class Wait implements Runnable {
            public void run() {
                // 加锁,拥有lock的Monitor
                synchronized (lock) {
                    // 当条件不满足时,继续wait,同时释放了lock的锁
                    while (flag) {
                        System.out.println(Thread.currentThread().getName()
                                + " flag is true. wait@ "
                                + new SimpleDateFormat("HH:mm:ss")
                                .format(new Date()));
                        try {
                            lock.wait();
                            System.out.println("此处继续执行"+Thread.currentThread().getName());
    //                        flag=true;
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    // 条件满足时,完成工作
                    System.out.println(Thread.currentThread().getName()
                            + " flag is false. running@ "
                            + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                }
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+"执行结束");
                }
            }
        }
    
        // wait()会立刻释放synchronized(obj)中的obj锁,以便其他线程可以执行obj.notify()
        // 但是notify()不会立刻立刻释放sycronized(obj)中的obj锁,必须要等notify()所在线程执行完synchronized(obj)块中的所有代码才会释放这把锁.
        // yield(),sleep()不会释放锁
        static class Notify implements Runnable {
            public void run() {
                // 加锁,拥有lock的Monitor
                synchronized (lock) {
                    // 获取lock的锁,然后进行通知,通知时不会释放lock的锁,
                    // 直到当前线程释放了lock后,WaitThread才能从wait方法中返回
                    System.out.println(Thread.currentThread().getName()
                            + " hold lock. notify @ "
                            + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                    lock.notifyAll();
                    flag = false;
                }
                // 再次加锁
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName()
                            + " hold lock again. sleep@ "
                            + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                }
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+"执行结束");
                }
            }
        }
    }

      执行结果如下

    1  WaitThread flag is true. wait@ 20:50:39
    2  NotifyThread hold lock. notify @ 20:50:40
    3  NotifyThread hold lock again. sleep@ 20:50:40
    4  NotifyThread执行结束
    5  此处继续执行WaitThread
    6  WaitThread flag is false. running@ 20:50:40
    7  WaitThread执行结束

      解释:

      首先创建一个lock对象,然后给这个lock上锁来对多个进程同步,flag是一个标志,用来跳出while循环。

         当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。

      此时轮到notifythread线程,并且执行notifyAll(),这个意思是能够唤醒所有正在等待这个lock对象的monitor的线程,但是

      必须要等notify()所在线程执行完synchronized(obj)块中的所有代码才会释放这把锁,

      此时接着waitthread被唤醒,继续执行while循环,执行完之后,由于flag在notifythread中置为false,所以跳出while循环(如果在实例代码的wail()后加flag=true结果是截然不同,由于notirythread进程执行完,此时会一直陷入wait,大家可以试试),

      执行console打印5 6 7

      notify()与notifyAll()的区别 

      notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象

      的monitor的话,则只能唤醒其中一个线程

      而调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程

      当时的疑惑

      (1)既然notify或者notifyAll需要执行完synchronized块中的内容,那么他还有什么存在的价值的

        后来执行完之后,才发现要是没有这个方法,那么synchronized块执行完之后,waitthread还是在等待状态,无法被唤醒。

      (2)wait被notify唤醒之后,是接着执行,所以console打印5,并不是从头执行(如果在实例代码的wail()后加flag=true结果是截然不同,由于notirythread进程执行完,waitthread进程重新执行wait方法,此时会一直陷入wait,无其他进程唤醒此进程)

    二、wait()/wait(long)和sleep(long)方法的区别

      将示例代码中的lock.wait()改为Thread.sleep(1000),console打印

    WaitThread flag is true. wait@ 21:29:49
    此处继续执行WaitThread
    WaitThread flag is true. wait@ 21:29:50
    此处继续执行WaitThread
    WaitThread flag is true. wait@ 21:29:51
    此处继续执行WaitThread
    WaitThread flag is true. wait@ 21:29:52
    此处继续执行WaitThread

      由此说明sleep并没有释放锁。

      区别:

        1、Sleep(long)是Thread的方法,而wait()/wait(long)是Object的方法

        2、Sleep(long)可以放在sychnoized块内也可以不放在里面,但是wait()/wait(long)必须放在语句块内

        3、Sleep(long)不释放锁,只是让当前线程暂停一段时间,而wait()/wait(long)是释放锁

        4、wait()将当前线程放到阻塞队列,只有调用notify()/notifyAll()方法后,才将其从阻塞队列中移动到就绪队列,等待被CPU调度,而wait(long)方法执行后就是放到阻塞队列,等待时间到期或者被wait()/wait(long)唤醒后就可以放到就绪队列被CPU调度

      目前还有一个疑惑,就是线程中的run方法有两个同样的synchroized(lock),是不是跟一个synchroized(lock)效果是一样的,目前就运行结果来看是这样子的!

  • 相关阅读:
    BEM(Block–Element-Modifier)
    http://element.eleme.io/#/zh-CN/component/quickstart
    Commit message 的写法规范。本文介绍Angular 规范(
    好的commit应该长啥样 https://github.com/torvalds/linux/pull/17#issuecomment-5654674
    代码管理
    if you have content fetched asynchronously on pages where SEO is important, SSR might be necessary
    Martin Fowler’s Active Record design pattern.
    The Zen of Python
    Introspection in Python How to spy on your Python objects Guide to Python introspection
    Object-Oriented Metrics: LCOM 内聚性的度量
  • 原文地址:https://www.cnblogs.com/sxkgeek/p/9061798.html
Copyright © 2011-2022 走看看