精华内容
下载资源
问答
  • notify notifyAll

    2013-08-09 10:47:13
    2. notifynotifyall都只会唤醒本对象锁定的线程,区别在于,notify只会任选一个本对象锁定的wait的线程,而这个线程的实现往往是 while(condition) wait, 如果这个线程又发现条件 condition还是不满足,还是进入...
    package info;
    
    import  java.util.concurrent.*;
    
    class Blocker {
    	private boolean stop = false;
    	synchronized void waitingCall() {
    		try {
    			while (!stop) {
    				System.out.println(Thread.currentThread() + "begin to wait");
    				wait();
    				System.out.println(Thread.currentThread() + " waiting");
    			}
    		}
    		catch(InterruptedException e) {
    			System.out.println(Thread.currentThread() + "catch");
    		}
    		System.out.println(Thread.currentThread() + "over");
    	}
    	
    	public void setStop() {
    		stop = true;
    	}
    	
    	synchronized void prod(){ notify(); }
    	synchronized void prodAll() {notifyAll(); }
    }
    
    class Task implements Runnable {
    	static Blocker block = new Blocker();
    	public void run() {
    		block.waitingCall();
    	}
    }
    
    public class Factory {
    	
    	
    	public static void main(String[] args) {
    		ExecutorService exe = Executors.newCachedThreadPool();
    		for (int i = 0; i < 5; ++i)
    			exe.execute(new Task());
    		try {
    		Thread.sleep(2000);
    		}
    		catch (InterruptedException e) {
    			
    		}
    		Task.block.setStop();
    		//Task.block.prod();//只会执行完一个线程
    		Task.block.prodAll();//会检测每一个waiting的线程,如果满足条件,就唤醒并执行完
    		
    	}
    
    }
    


    prodAll:

    Thread[pool-1-thread-1,5,main]begin to wait
    Thread[pool-1-thread-2,5,main]begin to wait
    Thread[pool-1-thread-3,5,main]begin to wait
    Thread[pool-1-thread-5,5,main]begin to wait
    Thread[pool-1-thread-4,5,main]begin to wait
    Thread[pool-1-thread-4,5,main] waiting
    Thread[pool-1-thread-4,5,main]over
    Thread[pool-1-thread-5,5,main] waiting
    Thread[pool-1-thread-5,5,main]over
    Thread[pool-1-thread-3,5,main] waiting
    Thread[pool-1-thread-3,5,main]over
    Thread[pool-1-thread-2,5,main] waiting
    Thread[pool-1-thread-2,5,main]over
    Thread[pool-1-thread-1,5,main] waiting
    Thread[pool-1-thread-1,5,main]over


    prod:

    Thread[pool-1-thread-1,5,main]begin to wait
    Thread[pool-1-thread-3,5,main]begin to wait
    Thread[pool-1-thread-2,5,main]begin to wait
    Thread[pool-1-thread-4,5,main]begin to wait
    Thread[pool-1-thread-5,5,main]begin to wait
    Thread[pool-1-thread-1,5,main] waiting
    Thread[pool-1-thread-1,5,main]over


    //

    1. wait notify 必须在同步块中执行,或者获取锁之后执行. 
        注意wait,notify是基于对象的而不是线程
        wait的内部实现是:1.释放锁;2. 等待收到notify的信号,否则就一直堵塞(注意此时不占用cpu);3. 加锁
        notify的内部实现是:仅仅是发送信号,不会释放锁,由外部决定释放锁的操作

    从中可以总结出,wait和notify必须要被同步块包围。

    2. notify和notifyall都只会唤醒本对象锁定的线程,区别在于,notify只会任选一个本对象锁定的wait的线程,而这个线程的实现往往是 while(condition) wait, 如果这个线程又发现条件        condition还是不满足,还是进入wait阶段
     notifyall则会唤醒所有本对象锁定的wait线程, 但是处在wait的队列中的线程都必须依次获取到对象的锁,进行下部的执行


    3. wait(timeout) 如果超过了timeout还是没有收到notify就会自动解除堵塞,执行下步操作


    通过synchronized同步也叫做是 Monitor同步,其自带了简单的线程间同步的notify和wait,但是灵活性比较差,这是因为这只是一个信号,所以一般而言只能表示一个状态的变化,而在同步逻辑中多个状态的变化也比较多。这时,就需要用到 ReentrantLock和其生成的Condition进行多个状态之间的同步。

    Java用wait/notify机制实际上默认给一个内部锁绑定了一个条件队列,但是,有时候,针对一个状态(锁),我们的程序需要两个或以上的条件队列,比如,刚才的Account例子,如果某个2B银行有这样的规定“一个账户存款不得多于10000元”,这个时候,我们的存钱需要满足“余额+要存的数目不大于10000,否则等待,直到满足这个限制”,取钱需要满足“余额足够,否则等待,直到有钱为止”,这里需要两个条件队列,一个等待“存款不溢出”,一个等待“存款足够”,这时,一个默认的条件队列够用么?你可能又说,够用,我们可以模仿network里的“多路复用”,一个队列就能当多个来使,像这样:

    public class Account {
    	public static final int BOUND = 10000;
    	private int balance;
    	
    	public Account(int balance) {
    		this.balance = balance;
    	}
    	
    	synchronized public boolean withdraw(int amount) throws InterruptedException{
    			while(balance<amount)
    				wait();// no money, wait
    			balance -= amount;
    			notifyAll();// not full, notify
    			return true;
    	}
    	
    	synchronized public void deposit(int amount) throws InterruptedException{
    			while(balance+amount >BOUND)
    				wait();//full, wait
    			balance +=amount;
    			notifyAll();// has money, notify
    	}
    }

    不是挺好吗?恩,没错,是可以。但是,仍然存在性能上的缺陷:每次都有多个线程被唤醒,而实际只有一个会运行,频繁的上下文切换和锁请求是件很废的事情。我们能不能不要notifyAll,而每次只用notify(只唤醒一个)呢?不好意思,想要“多路复用”,就必须notifyAll(有时,我们只希望唤醒一部分的堵塞线程,而不是全部的堵塞线程),否则会有丢失信号之虞(不解释了)。只有满足下面两个条件,才能使用notify:

    一,只有一个条件谓词与条件队列相关,每个线程从wait返回执行相同的逻辑。

    二,一进一出:一个对条件变量的通知,语义上至多只激活一个线程。


    比如ArrayBlockingQueue

    需要有两个状态,一个是队列是不是满了,另一个是队列是不是空的,用monitor实现就很复杂,这时就要用condition实现


    ArrayBlockingQueue 是jdk1.5 新提供的阻塞队列,实现了固定大小的队列。 

    功能: 
    1、阻塞的效果 。put时如果元素已经满,那么阻塞,get时 如果队列为空,那么阻塞。 
    2、是实现生产者消费者模型的极好的备选工具。 

    实现依赖: 
    1、lock锁(内存的可见性、互斥访问、限制编译器的代码优化调整) 
    2、Condition条件通知(线程间的协作)
     

    注意点:代码中多次用的signal 而不是signalAll 有原因的: 
    1、signalAll 唤醒所有等待的线程,事实上只能有一个通过获得锁,那么会增加锁竞争的几率。效率也低,如果用signal ,那么仅唤醒一个线程,这正是我们所需要的场景! 


    package java.util.concurrent;
    import java.util.concurrent.locks.*;
    import java.util.*;
    
    
    public class ArrayBlockingQueue<E> extends AbstractQueue<E>
            implements BlockingQueue<E>, java.io.Serializable {
    
        
        private static final long serialVersionUID = -817911632652898426L;
    
        /** 队列的项,底层是数组,final 修饰意味着 ArrayBlockingQueue 是固定大小的队列 */
        private final E[] items;
        /** 对数组items 下一个 take, poll or remove 操作的索引index */
        private int takeIndex;
        /** 对数组items 下一个 put, offer, or add 操作的索引index */
        private int putIndex;
        /**队列中数据项的数量 ,必须在lock当前锁的情况下才可以使用
         注意:count 不需要volitile 修饰, tackIndex putIndex 都一样,因为使用它们的场景都有lock 锁,所以内存可见性和编译代码调整的优化 得到安全的保障!!
         */
        private int count;
    
        /*
         * Concurrency control uses the classic two-condition algorithm
         * found in any textbook.
         */
    
        /**  数据访问的锁*/
        private final ReentrantLock lock;
        /** 非空等待条件 */
        private final Condition notEmpty;
        /** 非满等待条件 */
        private final Condition notFull;
    
    
    
    
        /**
         * 在数组的尾部放数据
         */
        public void put(E e) throws InterruptedException {
            if (e == null) throw new NullPointerException();
            final E[] items = this.items;
            final ReentrantLock lock = this.lock;//先加锁
            lock.lockInterruptibly();
            try {
                try {
                    while (count == items.length) //如果已经满,那么等待
                        notFull.await();
                } catch (InterruptedException ie) {
                    notFull.signal(); // 防止这个线程一直堵塞着,所以先要给自己signal下。或者,有这个极端情况:这个线程在堵塞时,抛出了中断异常,这时,却把notFull的信号发给了这个线程,
    				//如果不再把这个信号发出去,很容易造成所有线程的死锁。即使重复发了notFull信号,其他写线程还可以通过while循环来判断是不是真的不满
                    throw ie;
                }
                insert(e);
            } finally {//
                lock.unlock();
            }
        }
    	//如果用lock,则必须用finally来释放这个lock,防止有异常抛出,而导致永远不能释放锁
    	//如果用await,在catch的时候,最好要再发下这个信号
    	
    	
        /**
         * Inserts element at current put position, advances, and signals.
         * Call only when holding lock.
          当前的putIndex位置上放置x元素(只能在获取锁的情况下调用)
         */
        private void insert(E x) {
            items[putIndex] = x;
            putIndex = inc(putIndex); //插入数据后,下一个要插入的位置需要 +1
            ++count; //数量+1
            notEmpty.signal(); //含义:一旦插入新数据,那么需要通知notEmpty.wait 条件下等待的线程(take数据的线程)
        }
    
    
    
        public E take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                try {
                    while (count == 0) //如果为空,那么notEmpty  await 进入等待状态
                        notEmpty.await();
                } catch (InterruptedException ie) {
                    notEmpty.signal(); // propagate to non-interrupted thread
                    throw ie;
                }
                E x = extract();
                return x;
            } finally {
                lock.unlock();
            }
        }
    	
    	    /**
         * Extracts element at current take position, advances, and signals.
         * 取一个元素 (只能在获取锁的情况下调用)
         */
        private E extract() {
            final E[] items = this.items;
            E x = items[takeIndex];// 获取当前takeIndex的元素
            items[takeIndex] = null;
            takeIndex = inc(takeIndex); // 调整下一个获取元素的的位置
            --count; //数量要减一个
            notFull.signal(); //取出后,通知添加数据的线程,items已经不满了。因为这里只取了一个值,所以只要从堵塞在put上的写线程上任选一个激活就行了
            return x;
        }
    
    
        /**
         * 情况缓冲
         */
        public void clear() {
            final E[] items = this.items;
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                int i = takeIndex; //取元素的位置
                int k = count; //总元素的数量
                while (k-- > 0) {
                    items[i] = null;
                    i = inc(i); //让下一个元素的位置+1
                }
                count = 0;
                putIndex = 0;
                takeIndex = 0;
                notFull.signalAll(); //非满的条件通知,这样就可以让所有的堵塞在put函数的线程都依次获得锁,判断是不是满,并插入了
            } finally {
                lock.unlock();
            }
        }
    
        
    }
    
    





    展开全文
  • java notify notifyall 区别

    2017-04-20 11:47:04
    java notify notifyall 区别


    两者的前提必须是已经对象wait()了,notify是唤醒等待中的一个(随机的)获取对象锁,进入可运行状态,而notifyall是唤醒所有阻塞的线程同时去获得对象锁,得到了那个线程进入可运行状态。

    展开全文
  • 文章目录前言目标关键字一、notify 定义线程可以通过以下三种方式之一成为对象监视器的所有者:二、notifyAll定义总结参考 前言 莫信直中直,须防仁不仁。 目标 Object notify notifyAll基本概念 关键字 notify ...

    前言

    莫信直中直,须防仁不仁。


    目标

    Object notify notifyAll基本概念

    关键字

    notify notifyAll

    一、notify 定义

    唤醒正在此对象的监视器上等待的单个线程。如果有任何线程在此对象上等待,则选择其中一个唤醒。该选择是任意的,并且可以根据实现情况进行选择。线程通过调用其中一个wait方法在对象的监视器上等待。
    在当前线程放弃对该对象的锁定之前,唤醒的线程将无法继续。唤醒的线程将以通常的方式与任何其他可能正在主动竞争以在此对象上进行同步的线程竞争。例如,被唤醒的线程在成为锁定该对象的下一个线程时没有任何可靠的特权或劣势。
    此方法只能由作为该对象的监视器的所有者的线程调用。
    一次只能有一个线程拥有对象的监视器

    线程可以通过以下三种方式之一成为对象监视器的所有者:

    1 通过执行该对象的同步实例方法。
    2 通过执行在对象上同步的同步语句的主体。
    3 对于类类型的对象,通过执行该类的同步静态方法。

    二、notifyAll定义

    使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法,或者经过了指定的时间。
    当前线程必须拥有该对象的监视器。
    此方法使当前线程(称为T)将自己置于该对象的等待集中,然后放弃对该对象的所有同步声明。出于线程调度目的,线程T被禁用,并且在发生以下四种情况之一之前一直处于休眠状态:
    其他一些线程为此对象调用notify方法,并且线程T恰好被任意选择为要唤醒的线程。
    其他一些线程为此对象调用notifyAll方法。
    其他一些线程中断线程T。
    指定的实时量或多或少已经过去。但是,如果超时为零,则不考虑实时,线程只是等待直到通知。
    然后将线程T从该对象的等待集中删除,并重新启用线程调度。然后,它以通常的方式与其他线程竞争在对象上进行同步的权利。一旦它获得了对象的控制权,它对对象的所有同步声明都将恢复到原样-即,恢复到调用wait方法时的情况。然后,线程T从调用wait方法返回。因此,从等待方法返回时,对象和线程T的同步状态与调用等待方法时的状态完全相同。
    线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒。尽管在实践中这种情况很少发生,但是应用程序必须通过测试应该导致线程唤醒的条件来防范它,并在条件不满足时继续等待。
    换句话说,等待应该总是像这样循环执行:

        synchronized (obj) {
                   while (<condition does not hold>)
                       obj.wait(timeout);
                   ... // Perform action appropriate to condition
               }
    

    如果当前线程在等待之前或等待期间被任何线程中断,则抛出InterruptedException。如上所述,直到该对象的锁定状态恢复之前,不会引发此异常。
    请注意,wait方法将当前线程放入该对象的等待集中,因此仅解锁该对象;在线程等待时,当前线程可以在其上同步的所有其他对象保持锁定。
    此方法只能由作为该对象的监视器的所有者的线程调用。有关线程可以成为监视器所有者的方式的描述,请参见notify方法。

    参数:
    超时–等待的最长时间(以毫秒为单位)。
    抛出:
    IllegalArgumentException-如果超时值为负。
    IllegalMonitorStateException-如果当前线程不是对象监视器的所有者。
    InterruptedException-如果任何线程在当前线程等待通知之前或之时中断了当前线程。引发此异常时,将清除当前线程的中断状态。

    总结

    参考

    多留言多点赞你们的只支持是我坚持下去的动力,都支棱起来!!!

    展开全文
  • 背景: 在编写生产者 / 消费者代码时, 遇到了一些奇怪的现象, 例如超额生产 / 超额消费, 而这些的原因是由于我们对 wait notify notifyAll 的理解不正确 下面有一些多线程下使用 wait notify notifyAll 注意事项 ...

    背景: 在编写生产者 / 消费者代码时, 遇到了一些奇怪的现象, 例如超额生产 / 超额消费, 而这些的原因是由于我们对 wait notify notifyAll 的理解不正确

    下面有一些多线程下使用 wait notify notifyAll 注意事项

    • wait notify notifyAll 都要放在 synchronized 方法 / 代码块中, 否则运行异常 java.lang.IllegalMonitorStateException
    • 务必在 while 而不是 if 中使用 wait (). 因为当 wait () 被唤醒后, 此时条件可能已经改变, 是需要应该再次校验是否满足条件, 而不是直接往下运行代码. 索引使用 while 而不是 if
    • 使用 notifyAll () 而不是 notify (). notify () 表示通知某一个线程, 而 notifyAll () b 表示通知所有等待此锁的线程. 因为在多线程下, 如果仅仅使用 notify () 来通知其他线程, 可能会通知到相同类型的线程, 例如消费者线程通知到其他消费者线程, 这会导致生产者线程无法被通知到, 一直处于 wait () 的状态
    展开全文
  • Java多线程之wait notify notifyAll
  • notify notifyAll wait

    2015-08-25 18:32:57
     * notify notifyAll wait 使用   * 1 一个对象执行相应的方法  * (一个对象wait后,需要调用同一个对象的notify唤醒这个对象的wait,可以在不同线程执行)  * 2 个人理解方法执行必须在synchronize代码块...
  • JAVA线程 -- wait notify notifyAll
  • 文章目录Object类的wait notify notifyAll常见面试问题 Object类的wait notify notifyAll常见面试问题 手写生产者消费者设计模式 . 如下的连接中已有代码实现 ...代码多敲几遍, 再手写, 也可以在面试中, 被问到熟悉...
  • Java 多线程学习笔记 线程通讯 wait notify notifyAll的理解 wait()、 notify()、 notifyAll()是Object类的实例方法,是多线程之间通信的手段 2. wait():当某个条件无法满足,当前线程又没有能力解决时,等待直到...
  • notify notifyAll 死锁

    2018-02-23 15:11:00
    从一个死锁分析wait,notify,notifyAll 泡芙掠夺者关注 2017.08.24 22:00*字数 1361阅读 249评论 3喜欢 7赞赏 1 本文通过wait(),notify(),notifyAll()模拟生产者-消费者例子,说明为什么使用notify()...
  • Java - sleep yield wait notify notifyAll join 方法功能解析。方法的区别分析。线程几种状态分析。
  • wait notify notifyAll

    2016-06-28 22:16:00
    而另一个线程B调用了该对象的notify或者notifyAll方法,线程A收到通知后从对象的wait方法返回,进而执行后续操作,上述两个线程通过对象来完成交互,而对象上的wait和notify/notifyAll的关系就如同开关信号一样,...
  • wait notify notifyAll 都是Object类的方法  wait notify notifyAll都是对实例的wait set 进行操作 所以他们是Object的方法比较合适  另外 注意有synchronized修饰的方法 当线程A对实例obj进行操作时 会加锁 别...
  • 多线程的wait notify notifyall sleep stop interrupt join wait notify wait notify 都是object根类上的方法(貌似现在不太常用) wait调用之前 wait方法调用之前要先获得该对象的监视器锁,否则会报...
  • 文章目录wait notify notifyAll的特点 性质wait 的原理线程状态转换的特殊情况 wait notify notifyAll的特点 性质 执行wait notify notifyAll 之前, 必须首先获取到 monitor 否则抛出异常 notify 只能唤醒其中一个...
  • java notify notifyAll

    2015-11-05 14:21:00
    notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。 void notify(): 唤醒一个正在等待该对象的线程。void notifyAll(): 唤醒所有正在等待该对象的线程。 两者的最大区别在于: ...
  • wait notify notifyall

    2015-10-09 18:37:27
    resource.wait()使线程释放锁并进入wait状态(等待resource.notify() 或 resource.notifyAll(), 不是等待获得resource的锁). resource.notify()会唤醒一个在resource.wait状态的线程(具体哪个由操作系统调度),使那个...
  • join yield | wait notify notifyAll 一.使用:  Thread.sleep(long) 和Thread.yield()都是Thread类的静态方法,在调用的时候都是Thread.sleep(long)/Thread.yield()的方式进行调用。  join()...
  • java wait notify notifyall

    2017-02-25 17:18:50
    等待池---------------------wait(),notify(),notifyAll()  如果一个线程调用了某个对象的wait方法,那么该线程进入到该对象的等待池中(并且已经将锁释放),  如果未来的某一时刻,另外一个线程调用了相同对象的...
  • wait notify notifyAll理解

    2019-06-17 09:42:00
    2019独角兽企业重金招聘Python工程师标准>>> ...
  • 在多线程的情况下,由于同一进程的多个线程共享同一片存储空间,在... wait与notify是java同步机制中重要的组成部分。结合与synchronized关键字使用,可以建立很多优秀的同步模型。  synchronized(this){ }等价于pub
  • thread的wait notifyAll notify 只能在同步代码中调用。 wait 释放当前的锁,并进入等待状态,如果没有别的线程调用notifyall 或者notify() 则会一直处于等待状态: public class SynDemo { private Object lock; ...
  • notify notifyall override

    2011-08-15 10:07:23
    关于notify和nitifyall的区别,网上说的很多,这里不再细说。 记录一点自己原来模糊的地方: notify是唤醒等待线程中的第一个,这个没有问题,如果看到其他说法...notifyall唤醒全部线程,但是只有一个能执行(sync)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,110
精华内容 2,844
关键字:

notifynotifyall