Java并发编程——锁的等待与唤醒
发布日期:2021-05-07 08:40:41 浏览次数:26 分类:精选文章

本文共 4946 字,大约阅读时间需要 16 分钟。

1. wait和notify

1.1 使用场景

  • 使用场景1:线程1 list 个数不等于5,就 wait;线程2添加元素,尽管个数大于5, notify ,但线程2继续持有锁,不会释放,所以线程1等线程2执行完才会输出
public class MyContainer2 {   	//添加volatile,使lists在其他线程可见	volatile List lists=new ArrayList();		public void add(Object o) {   		lists.add(o);	}		public int size() {   		return lists.size();	}		public static void main(String[] args) {   		MyContainer2 c=new MyContainer2();				final Object lock=new Object();				new Thread(()->{   			synchronized (lock) {   				System.out.println("t1 start");				if(c.size()!=5) {   					try {   						lock.wait();					} catch (InterruptedException e) {   						// TODO Auto-generated catch block						e.printStackTrace();					}				}				System.out.println("t1 end");			}		},"t1").start();				try {   			TimeUnit.SECONDS.sleep(1);		} catch (InterruptedException e1) {   			// TODO Auto-generated catch block			e1.printStackTrace();		}				new Thread(()->{   			System.out.println("t2 start");			synchronized (lock) {   				for(int i=0;i<10;i++) {   					c.add(new Object());					System.out.println("add "+i);										if(c.size()>5) {   						lock.notify();					}										try {   						TimeUnit.SECONDS.sleep(1);					} catch (InterruptedException e) {   						// TODO Auto-generated catch block						e.printStackTrace();					}				}			}			System.out.println("t2 end");					},"t2").start();												}}t1 startt2 startadd 0add 1add 2add 3add 4add 5add 6add 7add 8add 9t2 endt1 end
  • 使用场景2:让线程2先释放锁,线程1执行完,再让线程2执行
public class MyContainer3 {   	//添加volatile,使lists在其他线程可见	volatile List lists=new ArrayList();		public void add(Object o) {   		lists.add(o);	}		public int size() {   		return lists.size();	}		public static void main(String[] args) {   		MyContainer3 c=new MyContainer3();				final Object lock=new Object();				new Thread(()->{   			synchronized (lock) {   				System.out.println("t1 start");				if(c.size()!=5) {   					try {   						lock.wait();					} catch (InterruptedException e) {   						// TODO Auto-generated catch block						e.printStackTrace();					}				}				System.out.println("t1 end");				//通知t1继续执行				lock.notify();											}		},"t1").start();				try {   			TimeUnit.SECONDS.sleep(1);		} catch (InterruptedException e1) {   			// TODO Auto-generated catch block			e1.printStackTrace();		}				new Thread(()->{   			System.out.println("t2 start");			synchronized (lock) {   				for(int i=0;i<10;i++) {   					c.add(new Object());					System.out.println("add "+i);										if(c.size()==5) {   						lock.notify();						//让t2释放锁,让t1执行						try {   							lock.wait();						} catch (InterruptedException e) {   							// TODO Auto-generated catch block							e.printStackTrace();						}											}										try {   						TimeUnit.SECONDS.sleep(1);					} catch (InterruptedException e) {   						// TODO Auto-generated catch block						e.printStackTrace();					}				}			}			System.out.println("t2 end");					},"t2").start();			}}

1.2 原理

使用 wait() 和 notify() 一定要放在同步代码块中,关联一个监视器对象,被 wait() 的线程会被记录到 Wait Set 等待队列中,被阻塞的线程会记录到 Entry Set 阻塞队列中

使用 notifyAll() :Wait Set 中被唤醒的线程会与 Entry Set 中被唤醒的线程以及其他(可能的)活跃线程共同参与抢夺锁资源。如果其中一个被唤醒的等待线程成功申请到锁,那么该线程就会从 Wait Set 中移除。否则,这些被唤醒的线程仍然停留在 Wait Set 中,并再次被暂停,以等待下次申请锁的机会。

public class Object {   	//...	public final void wait() throws InterruptedException {           wait(0);    }    public final native void wait(long timeout) throws InterruptedException;    public final native void notify();}

2. await 和 signal

2.1 使用场景

public class MyContainer3  {       final Lock lock = new ReentrantLock();    // condition 依赖于 lock 来产生    final Condition notFull = lock.newCondition();    final Condition notEmpty = lock.newCondition();    final Object[] items = new Object[100];    int putptr, takeptr, count;    // 生产    public void put(Object x) throws InterruptedException {           lock.lock();        try {               while (count == items.length)                notFull.await();  // 队列已满,等待,直到 not full 才能继续生产            items[putptr] = x;            if (++putptr == items.length) putptr = 0;            ++count;            notEmpty.signal(); // 生产成功,队列已经 not empty 了,发个通知出去        } finally {               lock.unlock();        }    }    // 消费    public Object take() throws InterruptedException {           lock.lock();        try {               while (count == 0)                notEmpty.await(); // 队列为空,等待,直到队列 not empty,才能继续消费            Object x = items[takeptr];            if (++takeptr == items.length) takeptr = 0;            --count;            notFull.signal(); // 被我消费掉一个,队列 not full 了,发个通知出去            return x;        } finally {               lock.unlock();        }    }}

2.2 原理

public interface Lock {       void lock();    void lockInterruptibly() throws InterruptedException;    boolean tryLock();    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;        void unlock();    Condition newCondition();}public interface Condition {   	//...	void await() throws InterruptedException;	void signal();}
上一篇:4.监控redis(redis_exporter)
下一篇:3.监控linux(node_exporter)

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月14日 14时33分12秒