精华内容
下载资源
问答
  • wait和notify使用场景

    2020-12-20 10:27:42
    1.wait和notify方法必须要在同步块或者方法里面且成对出现使用 2.先waitnotify才ok 传统的synchronizedLock实现等待唤醒通知的约束 线程先要获得并持有锁,必须在锁块(synchronized或Lock)中 必须要先等待后唤醒...

    1.wait和notify方法必须要在同步块或者方法里面且成对出现使用
    2.先wait后notify才ok

    传统的synchronized和Lock实现等待唤醒通知的约束
    线程先要获得并持有锁,必须在锁块(synchronized或Lock)中
    必须要先等待后唤醒,线程才能够被唤醒

    LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
    LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法,归根结底,LockSupport调用Unsafe中的native代码

    LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个Permit(许可)
    permit只有两个值1和0,默认是0
    可以把许可看成是一种(0,1)信号量(Seamphore),但与Seamphore不同的是,许可的累加上限是1.

    为什么可以先唤醒线程后阻塞线程?
    因为unpark获得了一个凭证,之后再调取park方法,就可以名正言顺的凭证消费,故不会阻塞。

    形象的理解
    线程阻塞需要消耗凭证(permit),这个凭证最多只有1个。
    当调用park方法时
    如果有凭证,则会直接消耗掉这个凭证然后正常退出;
    如果无凭证,就必须阻塞等待凭证可以用
    而unpark则相反,它会增加一个凭证,但凭证最多只能有1个,累加无效

    为什么唤醒两次后阻塞两次,但最终结果还是会阻塞线程?
    因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark一样,只会增加一个凭证,而调用两次park却需要消费两个凭证,证不够,不能放行。

    展开全文
  • wait和notify是Java中的两个方法,可以用于线程间的协作,最典型的应用就是生产消费者模式。不过,没有真正用过的同学可能会认为它们是Thread或者Runnable的方法,其实不然,它们是Object父类的方法。 先看下...

    wait、notify方法介绍

    wait和notify是Java中的两个方法,可以用于线程间的协作,最典型的应用就是生产和消费者模式。不过,没有真正用过的同学可能会认为它们是Thread或者Runnable的方法,其实不然,它们是Object父类的方法。

    先看下Object.java中wait和notify方法的定义:
    wait方法:

        public final void wait(long millis) throws InterruptedException {
            wait(millis, 0);
        }
    
        public final native void wait(long millis, int nanos) throws InterruptedException;
    
        public final native void wait() throws InterruptedException;
    

    notify方法:

        public final native void notify();
    
        public final native void notifyAll();
    

    可以看出,wait和notify都是native方法,具体实现可能涉及效率考虑,所以通过native代码去实现了。

    Launcher中的应用场景分析

    以Launcher启动时,加载数据和绑定界面为例,这里通过wait和notify的使用,保证了UI线程优先执行。

    以下是LauncherModel的startLoaderForResults方法,调用后会启动工作线程开始加载和绑定流程

        public void startLoaderForResults(LoaderResults results) {
            synchronized (mLock) {
                stopLoader();
                mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, sBgDataModel, results);
                runOnWorkerThread(mLoaderTask);
            }
        }
    

    LoaderTask实现了Runnalbe接口,它的run方法中,就是具体的实现了。从注释可以看到,分了好多步骤去加载数据和绑定界面,执行的任务还是挺繁重的,为了简洁明了的说明问题,这里去掉了后面部分代码,只保留了loadWorkspace、bindWorkspace、loadAllApps和bindAllApps实现代码。

        public void run() {
            synchronized (this) {
                // Skip fast if we are already stopped.
                if (mStopped) {
                    return;
                }
            }
    
            TraceHelper.beginSection(TAG);
            try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
                TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
                loadWorkspace();
    
                verifyNotStopped();
                TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
                mResults.bindWorkspace();
    
                // Notify the installer packages of packages with active installs on the first screen.
                TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast");
                sendFirstScreenActiveInstallsBroadcast();
    
                // Take a break
                TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle");
                waitForIdle();
                verifyNotStopped();
    
                // second step
                TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
                loadAllApps();
    
                TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
                verifyNotStopped();
                mResults.bindAllApps();
    
    			......
    
                transaction.commit();
            } catch (CancellationException e) {
                // Loader stopped, ignore
                TraceHelper.partitionSection(TAG, "Cancelled");
            }
            TraceHelper.endSection(TAG);
        }
    

    run方法运行在工作线程,mResults.bindWorkspace()方法实现其实是启动的UI线程在绑定界面,虽然run方法是工作线程,可以继续做自己的事情,而且正常不会导致ANR,但是在主线程高负荷刷新和渲染界面的时候,如果存在后台线程也在忙碌运转的话,主线程多少还是会受到影响的,CPU时间片肯定会减少,界面加载时间就会变长,这不是我们愿意看到的。

    在Launcher这样的应用中,更是不能容忍,看看上面代码中的注释‘Take a break’,在继续loadAllApps之前,工作线程做了一个暂停,为什么要这样做呢?这其实是在给bindWorkspace让路,延迟loadAllApps,实现线程暂停的就是waitForIdle()方法。

    看下waitForIdle()的实现,用到了while循环,看起来还是在做事情,没有wait之类的方法暂停线程,但是调用了LooperIdleLock的awaitLocked(1000)方法

        protected synchronized void waitForIdle() {
            // Wait until the either we're stopped or the other threads are done.
            // This way we don't start loading all apps until the workspace has settled
            // down.
            LooperIdleLock idleLock = mResults.newIdleLock(this);
            // Just in case mFlushingWorkerThread changes but we aren't woken up,
            // wait no longer than 1sec at a time
            while (!mStopped && idleLock.awaitLocked(1000));
        }
    

    继续往下看LooperIdleLock的的实现

    public class LooperIdleLock implements MessageQueue.IdleHandler, Runnable {
    
        private final Object mLock;
    
        private boolean mIsLocked;
    
        public LooperIdleLock(Object lock, Looper looper) {
            mLock = lock;
            mIsLocked = true;
            if (Utilities.ATLEAST_MARSHMALLOW) {
                looper.getQueue().addIdleHandler(this);
            } else {
                // Looper.myQueue() only gives the current queue. Move the execution to the UI thread
                // so that the IdleHandler is attached to the correct message queue.
                new LooperExecutor(looper).execute(this);
            }
        }
    
        @Override
        public void run() {
            Looper.myQueue().addIdleHandler(this);
        }
    
        @Override
        public boolean queueIdle() {
            synchronized (mLock) {
                mIsLocked = false;
                mLock.notify();
            }
            return false;
        }
    
        public boolean awaitLocked(long ms) {
            if (mIsLocked) {
                try {
                    // Just in case mFlushingWorkerThread changes but we aren't woken up,
                    // wait no longer than 1sec at a time
                    mLock.wait(ms);
                } catch (InterruptedException ex) {
                    // Ignore
                }
            }
            return mIsLocked;
        }
    }
    

    awaitLocked方法中调用了mLock.wait(ms),每次调用一次会等待1秒钟,如果while循环判断mIsLocked为true,就会一直等待下去,直到外部线程调用了mLock的notify方法。

    全局搜索了launcher的代码后,发现只有两个地方调用了notify方法:
    一处是LooperIdleLock的queueIdle方法:

        @Override
        public boolean queueIdle() {
            synchronized (mLock) {
                mIsLocked = false;
                mLock.notify();
            }
            return false;
        }
    

    queueIdle方法是MessageQueue.IdleHandler接口的方法,从上面LooperIdleLock的代码实现可以看出,LooperIdleLock实现了这个接口

        public LooperIdleLock(Object lock, Looper looper) {
            mLock = lock;
            mIsLocked = true;
            if (Utilities.ATLEAST_MARSHMALLOW) {
                looper.getQueue().addIdleHandler(this);
            } else {
                // Looper.myQueue() only gives the current queue. Move the execution to the UI thread
                // so that the IdleHandler is attached to the correct message queue.
                new LooperExecutor(looper).execute(this);
            }
        }
    

    LooperIdleLock在构造函数中,通过looper.getQueue().addIdleHandler(this)往主线程消息队列中注册了这个接口,主线程空闲时,会回调queueIdle方法,进而通知work线程,不用等待了。

    另一处是LoaderTask的stopLocked方法:

        public synchronized void stopLocked() {
            mStopped = true;
            this.notify();
        }
    

    这个方法是用来停止加载和绑定流程的,结束流程的同时,当然也要结束工作线程中正在执行的任务,停止等待,notify就是用于唤醒线程,让它结束任务。

    总结

    不知不觉对于Launcher中wait和notify的应用已经分析完毕,应用场景即,在UI线程bindWorkspace时候,通过wait停止线程,等Workspace绑定结束再去loadAllApps,而notify在Workspace绑定结束后会被调用,从而唤醒线程继续执行loadAllApps,这个应用保证了UI线程优先执行。

    通观整个AOSP launcher也就这一个地方用到了wait和notify,可见平时我们基本用不到,只有在特定的场景才会遇到。

    展开全文
  • wait/notify/notifyall的使用场景

    千次阅读 2019-08-03 14:20:45
    wait/notify/notifyall的使用场景 1.wait使当前线程阻塞,前提是线程必须获得锁,所以一般配合synchronized使用。 2.线程执行wait的时候,会释放当前的锁,然后让出cpu,进入等待状态。 3.wait方法需要被try ...

    wait/notify/notifyall的使用场景

    1.wait使当前线程阻塞,前提是线程必须获得锁,所以一般配合synchronized使用。

    2.线程执行wait的时候,会释放当前的锁,然后让出cpu,进入等待状态。

    3.wait方法需要被try catch包含。

    4.wait/notify/notifyall的使用场景

    (1)生产者/消费者模型的实现

    注意点:

    a.假死

    当有多个生产者或者消费者的时候,使用的是notify而不是notifyall,那么有可能唤醒的是同类的,即有可能生产者唤醒的是生产者,消费者唤醒的是消费者。

    解决办法:使用notifyall

    b.生产者/消费者使用if判断的话会导致程序错乱。

    如果生产者是往list数组中存放数据,list数组的最大容量为1,消费者执行的是list.remove(0),如果使用if,有多个消费者的情况下,有可能其中一个消费者执行了remove(0),另一个消费者执行的时候就会报错。

    解决的办法:使用while代替if。

    (2)future模式的实现

    future主要四个类:

    Data接口(包含getRequest接口),FutureData实现Data接口,RealData实现Data接口,FutureClient供用户调用。

    用户通过FutureClient请求数据的时候,先返回FutureData,在开启一个线程往FutureData中设置RealData的数据,当用户请求调用getRequest的时候,如果数据还没构造好,则调用wait进行阻塞,同时调用while进行轮询查看数据是否准备好(isReay字段,boolean类型),当数据构造好的时候,isReay字段置为true。

    参看资料:

    https://www.jianshu.com/p/444cbe1691be

     

     

     

    展开全文
  • 今天去凤凰网面试了,可惜自己准备的东西都没有面到,有些紧张,其间有问到一个waitnotify使用场景,答曰:生产者与消费者模式,当时只写了个大概,现在将代码贴出。 储存柜 package cuspro; import java....

    今天去凤凰网面试了,可惜自己准备的东西都没有面到,有些紧张,其间有问到一个wait,notify的使用场景,答曰:生产者与消费者模式,当时只写了个大概,现在将代码贴出。

    储存柜

    package cuspro;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Storage {
    	private List<Object> foods;
    	
    	public final static int MAX_SIZE = 5;
    	
    	public Storage(){
    		foods = new ArrayList<Object>();
    	}
    	public List<Object> getFoods() {
    		return foods;
    	}
    
    	public void setFoods(List<Object> foods) {
    		this.foods = foods;
    	}
    	
    	
    }
    

     运行类,内部有:生产者,消费者两个内部类实现了Runnable接口:

    package cuspro;
    
    public class Company {
    	public static void main(String[] args) {
    		Company c = new Company();
    		Object lock = new Object();
    		Storage storage = new Storage();
    		try {
    			Thread.sleep(1000);
    		} catch (InterruptedException e1) {
    			e1.printStackTrace();
    		}
    		new Thread(c.new Customer(storage, lock)).start();
    		new Thread(c.new Producer(storage, lock)).start();
    		new Thread(c.new Customer(storage, lock)).start();
    		new Thread(c.new Producer(storage, lock)).start();
    		new Thread(c.new Customer(storage, lock)).start();
    		new Thread(c.new Producer(storage, lock)).start();
    		new Thread(c.new Customer(storage, lock)).start();
    		new Thread(c.new Producer(storage, lock)).start();
    		new Thread(c.new Customer(storage, lock)).start();
    		new Thread(c.new Producer(storage, lock)).start();
    		new Thread(c.new Customer(storage, lock)).start();
    		new Thread(c.new Producer(storage, lock)).start();
    
    	}
    
    	/**
    	 * 消费者
    	 * 
    	 * @author xtuali
    	 * 
    	 */
    	private class Customer implements Runnable {
    		private Storage storage;
    
    		private Object lock;
    
    
    		public Customer(Storage storage, Object lock) {
    			super();
    			this.storage = storage;
    			this.lock = lock;
    		}
    
    		public void run() {
    			while (true) {
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e1) {
    					e1.printStackTrace();
    				}
    				synchronized (lock) {
    					while (storage.getFoods().size() <= 0) {
    						try {
    							System.out.println("货物已空,提示生产者生产");
    							
    							lock.wait();   //当前线程在lock上等待,并释放锁
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    					storage.getFoods().remove(0);
    					lock.notifyAll(); //唤醒消费者与生产者
    					System.out.println("消费者消费1, "+Thread.currentThread().getName()+", 余量:"+storage.getFoods().size());
    				}
    			}
    		}
    	}
    
    	/**
    	 * 生产者
    	 * 
    	 * @author xtuali
    	 * 
    	 */
    	private class Producer implements Runnable {
    		private Storage storage;
    
    		private Object lock;
    		
    
    		public Producer(Storage storage, Object lock) {
    			super();
    			this.storage = storage;
    			this.lock = lock;
    		}
    
    		public void run() {
    			while (true) {
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e1) {
    					e1.printStackTrace();
    				}
    				synchronized (lock) {
    					while (storage.getFoods().size() >= Storage.MAX_SIZE) {
    						try {
    							System.out.println("货物已满,提示消费者消费");
    							
    							lock.wait(); //当前线程在lock上等待,并释放锁
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    					}
    					storage.getFoods().add(1);
    					lock.notifyAll();  //唤醒消费者与生产者
    					System.out.println("生产者生产1, "+Thread.currentThread().getName() +",余量:"+storage.getFoods().size());
    				}
    			}
    		}
    	}
    }
    

     之前考虑在Customer与Producer内部申明两个lock,一个是用来与Producer线程来通信,一个是用来与Customer线程来通信,但是锁没法释放,所以就只用了一个lock,但是这一个lock也解决了问题了!

    展开全文
  • wait和notify方法的使用

    2020-09-15 20:45:43
    wait和notify方法的使用 1.wait notify 均为 Object 的方法 Object.wait() —— 暂停一个线程 Object.notify() —— 唤醒一个线程 2.使用这两个方法时,我们需要先有一个Object对象,配合synchronize使用 3....
  • (1)可以使用wait()和notify()方法在Java中实现线程间通信。不只是一个或两个线程,而是多个线程可以使用这些方法相互通信。 (2)在synchronized方法或synchronized块中调用wait(),notify()notifyAll()...
  • 首先请考虑这样的场景:  你用饿了么点了份外卖,然后你是希望外卖到了的时候外卖小哥主动打电话给你,还是你不停的打电话问外卖小哥有没有送到呢? 分析一下这两种情况: 一:外卖小哥主动打电话通知你外卖到了...
  • wait和notify

    2020-03-21 10:35:04
    1. 为什么要使用wait和notify 假设现在有一些员工(线程)要使用同一把算盘(共享资源)工作,为了保证线程的安全性,他们的老板就设置了一个房间(synchronized锁),在一个时间只有一个线程可以进入这个房间进行...
  • 线程的wait和notify

    2020-09-13 22:34:26
    wait notify 必须在同步块里才可使用,即需要配合 synchronize 关键字使用。 典型的通知场景是,生产者消费者模型,线程 A 往队列中添加元素,线程 B 从队列中取出元素。 下面给一段示例代码: package ...
  • wait和notify机制

    2014-03-03 13:47:04
    典型的Wait-Notify场景一般与以下内容相关 1.状态变量(State Variable) 当线程需要wait的时候,总是因为一些状态不满足导致的。如往BlockQueue里面加入元素已满的时候。 2.条件断言(Condition Predicate) 当...
  • 文章目录概述场景引子synchronized wait/notify机制 概述 Java中线程通信协作的最常见的两种方式: syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll() ReentrantLock类加锁的线程的Condition类的await...
  • JAVA的wait和notify

    2018-02-20 17:24:21
    多线程经常会接触到线程交互场景wait和notify、notifyAll就是起到这个作用,三个方法必须要在synchronized锁区域内执行,也就是必须要有当前对象的monitor(锁)。 wait: 阻塞当前线程,交出锁的控制权,等待下一...
  • 今天去凤凰网面试了,可惜自己准备的东西都没有面到,有些紧张,其间有问到一个waitnotify使用场景,答曰:生产者与消费者模式,当时只写了个大概,现在将代码贴出。 储存柜 package cuspro; import java....
  • 线程通信之wait和notify

    2018-11-19 13:29:18
    layout: post title: "线程通信之wait和notify" subtitle: " "Object.wait()/notify()"" date: 2018-10-07 08:00:00 author: "青乡" header-img: "img/post-bg-2015.jpg" catalog: true tags: - multi...
  • wait 和notify使用的时候有很多的限制: 例如必须用在schronized的同步块里面,因为他们依赖于schronized里面的锁。 wait和notify不能指定唤醒哪一个线程,只能随机的返回一个线程。 当使用调用wait时,虽然当前...
  • 前面介绍了Synchronized关键词的原理与优化分析,Synchronized的重要不言而喻, 而作为配合Synchronized使用的另外两个关键字也显得格外重要. 今天, 来聊聊配合Object基类的 wait() notify() 这两个方法的...
  • 一文讲清多线程的wait和notify,notifyAll前言头牌‘赛铁花’注意细节白话wait/notify/notifyAll原理Wait/notify/notifyAll用法wait/notify/notifyAll实现原理及结论wait/notify/notifyall的应用场景 前言 很多同学...
  • 本文转载自:Java 多线程(七) 线程间的通信——waitnotify方法 1. 线程间通信  一些场景下,需要多个线程之间协调通信,来共同完成一件任务。java中Object类中相关的方法有两个...因为wait和notify方法定...
  • 线程同步的时候比较普世的方法就是wait和notify/notifyall来搭配使用,如下所示,这段非常的经典,用于同步过程绝对安全。 package com.company; public class A { private boolean condition; private Object ...
  • 1. 多线程中wait和notify方法请先阅读下我的博客中关于线程的状态的两篇文章后,再来阅读这篇文章,药物配合吃,疗效更加【坏笑】。 http://blog.csdn.net/duxingxia_007/article/details/49310275 ...
  • 综述Java的wait()、notify()学习三部曲由三篇文章组成,内容分别是:一、通过阅读openjdk8的源码,分析理解waitnotify在JVM中的具体执行...
  • 一、场景 ...第二种方式:就是利用线程之间的通信机制,也就是wait和notify,如果list存放的订单达到了最大限制或者list为空(大小为0),则wait,阻塞线程,否则notify,唤醒线程。 二、wait和not...
  • Wait-Notify机制

    2016-11-26 18:22:36
    转自:Wait-Notify机制http://www.ticmy.com/?p=219 Wait-Notify机制可以说是实现阻塞操作较为高效的一种方式。虽然在实际中鼓励使用类库中已有...典型的Wait-Notify场景一般与以下内容相关: 1、状态变量(State
  • 前面介绍wait和notify的基本语义,参考条件队列大法好:wait和notify的基本语义。这篇讲讲使用waitnotify、notifyAll的正确姿势。 一定要先看语义,保证自己掌握了基本语义,再来学习如何使用。 基本原理 状态...
  • 勉强算是个难点场景:我集成了讯飞语音,想封装下,...一开始我的做法是愚蠢的:在调用startSpeaking(String)后进行wait,然后在speak结束的回调中notify,思路没问题,可是主线程anr了,主线程等不起,犯了一个低级...
  • synchronized解决的是资源竞争问题,多线程协调的问题需要wait()和notify()解决。 以多线程任务队列的场景举例。 class TaskQueue { Queue<String> queue = new LinkedList<>(); public synchronized...
  • waitnotify和notifyAll

    2020-04-01 10:59:29
    生产者消费者模型是我们学习多线程知识的一个经典案例,一个典型的生产者消费者模型如下: public void produce() { synchronized (this) { while (mBuf.isFull()) { try { wait(); ...
  • java中的waitnotify

    2018-07-24 20:40:47
    最近在学习java多线程的锁相关的知识,通过不断百度别人对waitnotify的理解,我也有了一些的认识。同时之所以写这篇博客,我也是发现网上大多写的是waitnotify的用法、规则、注意事项、描述性比较专业、太技术...
  • 上篇中已经介绍了wait()、notify()、notifyAll()是对象的方法,再补充一下,既然wait交出的是对象的控制权,notify唤醒的是等待这个对象控制权的线程,那么在使用的时候wait和notify需要注意多个线程抢夺释放的是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,906
精华内容 13,162
关键字:

wait和notify的使用场景