`

java锁之wait,notify(wait会释放锁,notify仅仅只是通知,不释放锁)

    博客分类:
  • java
 
阅读更多

   wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行, 只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还 在别人手里,别人还没释放。如果notify/notifyAll方法后面的代码还有很多,需要这些代码执行完后才会释放锁),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

 

   1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

 

 2)当前线程必须拥有此对象的monitor(即锁),才能调用某个对象的wait()方法能让当前线程阻塞,

       (这种阻塞是通过提前释放synchronized锁,重新去请求锁导致的阻塞,这种请求必须有其他线程通过notify()或者notifyAll()唤醒重新竞争获得锁

 

 3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

      (notify()或者notifyAll()方法并不是真正释放锁,必须等到synchronized方法或者语法块执行完才真正释放锁

 

 4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度

 

  例子1(错误使用导致线程阻塞):三个线程,线程3先拥有sum对象的锁,然后通过sum.notify()方法通知等待sum锁的线程去获得锁,但是这个时候线程1,2并没有处于wait()导致的阻塞状态,而是在synchronized方法块处阻塞了,所以,这次notify()根本没有通知到线程1,2。然后线程3正常结束,释放掉sum锁,这个时候,线程1就立刻获得了sum对象的锁(通过synchronized获得),然后调用sum.wait()方法释放掉sum的锁,线程2随后获得了sum对象的线程锁(通过synchronized获得),这个时候线程1,2都处于阻塞状态,但是悲催的是,这之后再也没有线程主动调用sum.notify()或者notifyAll()方法显示唤醒这两个线程,所以程序阻塞

public class CyclicBarrierTest {
	
	public static void main(String[] args) throws Exception {
		final Sum sum=new Sum();
		
		new Thread(new Runnable() {
			@Override
			public void  run() {
				try {
					synchronized (sum) {
						System.out.println("thread3 get lock");
						sum.sum();
						sum.notifyAll(); //此时唤醒没有作用,没有线程等待
						Thread.sleep(2000);
						System.out.println("thread3 really release lock");
					}
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void  run() {
				try {
					synchronized (sum) {
						System.out.println("thread1 get lock");
						sum.wait();//主动释放掉sum对象锁
						System.out.println(sum.total);
						System.out.println("thread1 release lock");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void  run() {
				try {
					synchronized (sum) {
						System.out.println("thread2 get lock");
						sum.wait();  //释放sum的对象锁,等待其他对象唤醒(其他对象释放sum锁)
						System.out.println(sum.total);
						System.out.println("thread2 release lock");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
	      
}

class Sum{
	public Integer total=0;
	
	public void  sum() throws Exception{
		total=100;
		Thread.sleep(5000);
	}
	
}
 

 

    运行结果:

 

thread3 get lock
thread3 really release lock
thread2 get lock
thread1 get lock
//程序后面一直阻塞
 例子2:还是上面程序,顺序不同,把线程3放到最下面。最后线程1,2都因为没有再次获得线程导致线程阻塞

 

运行过程:

线程1先运行获得sum对象锁(通过synchronized),但是随后执行了sum.wait()方法,主动释放掉了sum对象锁,然后线程2获得了sum对象锁(通过synchronized),也通过sum.wait()失去sum的对象锁,最后线程3获得了sum对象锁(通过synchronized),主动通过sum.notify()通知了线程1或者2,假设是1,线程1重新通过notify()/notifyAll()的方式获得了锁,然后执行完毕,随后线程释放锁,然后这个时候线程2成功获得锁,执行完毕。

public class CyclicBarrierTest {
	
	public static void main(String[] args) throws Exception {
		final Sum sum=new Sum();
		
	
		
		new Thread(new Runnable() {
			@Override
			public void  run() {
				try {
					synchronized (sum) {
						System.out.println("thread1 get lock");
						sum.wait();//主动释放sum对象锁,等待唤醒
						System.out.println(sum.total);
						System.out.println("thread1 release lock");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void  run() {
				try {
					synchronized (sum) {
						System.out.println("thread2 get lock");
						sum.wait();  //主动释放sum对象锁,等待唤醒
						System.out.println(sum.total);
						System.out.println("thread2 release lock");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void  run() {
				try {
					synchronized (sum) {
						System.out.println("thread3 get lock");
						sum.sum();
						sum.notifyAll();//唤醒其他等待线程(线程1,2)
						Thread.sleep(2000);
						System.out.println("thread3 really release lock");
					}
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		
	}
	      
}

class Sum{
	public Integer total=0;
	
	public void  sum() throws Exception{
		total=100;
		Thread.sleep(5000);
	}
	
}

 

执行结果:

thread1 get lock
thread2 get lock
thread3 get lock
thread3 really release lock
100
thread2 release lock
100
thread1 release lock

 

 

 

 

 

分享到:
评论

相关推荐

    Java 同步锁 wait notify 学习心得

    `wait()`方法使当前线程释放锁并进入等待状态,直到接收到通知或超时(如果是`wait(long timeout)`)。这意味着线程将暂停执行,并且不会消耗CPU资源,直到被唤醒。使用`wait()`的一个关键前提是在`synchronized`...

    java之wait,notify的用法([ 详解+实例 ])

    wait和notify方法的主要区别在于,wait方法会释放锁,而notify方法不会释放锁。wait方法用于让当前线程进入等待状态,而notify方法用于唤醒等待的线程。 wait和sleep、suspend的区别 wait方法与sleep和suspend方法...

    39.线程间的通信-wait与notify-wait方法自动释放锁与notify方法不会释放锁.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    Java 同步方式 wait和notify/notifyall

    Java中的同步机制是多线程编程中至关重要的概念,它用于控制多个线程对共享资源的访问,防止数据不一致性和竞态条件的发生。在Java中,`wait()`, `notify()`, 和 `notifyAll()` 是Java Object类的三个方法,它们在...

    Java多线程wait和notify

    `wait()` 方法会让当前持有锁的线程进入等待状态,释放锁,直到其他线程调用 `notify()` 或 `notifyAll()` 唤醒它。`notify()` 则会随机选择一个等待在该对象监视器上的线程并唤醒它,而 `notifyAll()` 则会唤醒所有...

    wait_notify_demo

    1. `wait()`: 当一个线程调用某个对象的`wait()`方法时,它会释放该对象的锁,并进入等待状态,直到其他线程调用了该对象的`notify()`或`notifyAll()`方法唤醒它。等待的线程不会自动恢复执行,而是需要重新竞争对象...

    源码—Java多线程5—死锁和wait notify notifyAll

    源码—Java多线程5—死锁和wait notify notifyAll

    java中几个notify、wait使用实例

    当一个线程调用`notify()`方法时,它会选择在等待队列中任意一个处于等待状态的线程进行唤醒,但并不释放锁,这意味着被唤醒的线程需要在下次获取锁时竞争。由于`notify()`只能唤醒一个线程,所以有时可能需要多次...

    Java的sychronized、wait和notify范例

    1. `wait()`:让当前持有锁的线程释放锁,并进入等待池,直到其他线程调用`notify()`或`notifyAll()`唤醒该线程。调用`wait()`后,线程会释放持有的锁,进入等待状态,直到其他线程执行`notify()`或`notifyAll()`,...

    等待机制与锁机制wait notify

    生产者生产完商品后调用`notify()`唤醒消费者,消费者在等待过程中调用`wait()`,释放锁并进入等待状态。这样就实现了线程间的协作。 需要注意的是,`wait()`、`notify()`和`notifyAll()`的调用者应当是持有对象锁...

    浅谈java多线程wait,notify

    当wait方法被调用时,当前线程会释放锁,让CommunicationThread2可以获得锁并执行。然后,我们使用notify方法来唤醒CommunicationThread2,并重新获得锁。 在CommunicationThread2中,我们也使用synchronized块来...

    wait和notify讲解

    wait和notify讲解

    一个理解wait()与notify()的例子

    - **`wait()`**:不仅让线程暂停,还会释放锁,允许其他线程执行同步代码块,提高并发性能。 #### 总结 通过本示例代码的学习,我们可以深入了解`wait()`与`notify()`方法的工作原理及其在Java多线程编程中的应用...

    java-wait和notify的用法.pdf

    `wait()`让线程暂停并释放锁,等待其他线程的通知;`notify()`则用来唤醒一个在对象上等待的线程。在实际编程中,需要正确地使用这些方法,确保线程安全和程序的正确性。理解这两个方法的工作原理以及如何在同步代码...

    wait()、notify()和notifyAll()方法2---马克-to-win java视频

    wait()、notify()和notifyAll()方法2---马克-to-win java视频

    Java多线程中wait、notify、notifyAll使用详解

    wait()方法是使当前线程自动释放占有的对象锁,并等待notify。该方法的调用必须在synchronized代码块或者方法中,因为wait()方法需要当前线程必须获得对象锁。在wait()方法执行时,当前线程会释放当前的锁,然后让出...

    如何在Java中正确使用 wait, notify 和 notifyAll

    举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓冲区中有内容待消费(不为空)。相应的,消费者可以通知生产者可以开始生成更多的数据,...

    主线程去控制子线程wait与notify

    主线程调用`wait()`后,会释放锁并进入等待池。 4. **改变共享资源**:主线程在完成某些操作后,可能需要改变共享资源的状态,比如设置标志位,增加计数器等。 5. **调用`notify()`**:一旦共享资源满足了唤醒子...

    详解Java程序并发的Wait-Notify机制

    在Java中,`wait()`, `notify()`, `notifyAll()`方法是`Object`类的成员,而不是`Thread`类的,这意味着任何对象都可以作为等待和通知的基础。 **1. 状态变量(State Variable)** 状态变量是线程间通信的关键。当...

    深入理解Wait、Notify和Wait与sleep区别

    1. **wait()**:当一个线程调用对象的`wait()`方法时,它会释放当前对象的锁,并进入等待池,直到其他线程调用同一对象的`notify()`或`notifyAll()`方法唤醒它。唤醒后,线程不会立即恢复执行,而是需要重新获取对象...

Global site tag (gtag.js) - Google Analytics