sleep和wait区别

1、sleep()方法
    sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;
    sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的机锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。
    在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。

2、wait()方法

    wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;

    wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。

   notify()和notifyAll()方法只是唤醒等待该对象的monitor(即锁)的线程,并不决定哪个线程能够获取到monitor(即锁)

    wait()必须放在synchronized block中,否则会在program runtime时抛出”java.lang.IllegalMonitorStateException“异常。

wait()方法在jdk文档中的解释如下:

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.


3、所以sleep()和wait()方法的最大区别是:
    sleep()睡眠时,保持对象锁,仍然占有该锁;
    而wait()睡眠时,释放对象锁。
    但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException(但不建议使用该方法)。


实例1,使用sleep.

package com.lee.thread;

public class SleepThread1 implements Runnable {
	int number = 10;

	public void firstMethod() throws Exception {
		synchronized (this) {
			number += 100;
			System.out.println(number);
		}
	}

	public void secondMethod() throws Exception {
		synchronized (this) {
			/**
			 * (休息2S,阻塞线程) 以验证当前线程对象的机锁被占用时, 是否被可以访问其他同步代码块
			 */
			Thread.sleep(2000);	//1. 把2注释掉,使用sleep;
			//this.wait(2000);	//2. 把1注释掉,使用wait;
			number *= 200;
		}
	}

	@Override
	public void run() {
		try {
			firstMethod();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		SleepThread1 sleepThread1 = new SleepThread1();
		Thread thread = new Thread(sleepThread1);
		thread.start();
		sleepThread1.secondMethod();
		
		System.out.println("number="+sleepThread1.number);
	}
}


结果:

2100
number=2100


实例2,使用wait

package com.lee.thread;

public class SleepThread1 implements Runnable {
	int number = 10;

	public void firstMethod() throws Exception {
		synchronized (this) {
			number += 100;
			System.out.println(number);
		}
	}

	public void secondMethod() throws Exception {
		synchronized (this) {
			/**
			 * (休息2S,阻塞线程) 以验证当前线程对象的机锁被占用时, 是否被可以访问其他同步代码块
			 */
			//Thread.sleep(2000);	//1. 把2注释掉,使用sleep;
			this.wait(2000);	//2. 把1注释掉,使用wait;
			number *= 200;
		}
	}

	@Override
	public void run() {
		try {
			firstMethod();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		SleepThread1 sleepThread1 = new SleepThread1();
		Thread thread = new Thread(sleepThread1);
		thread.start();
		sleepThread1.secondMethod();
		
		System.out.println("number="+sleepThread1.number);
	}
}


结果:

110
number=22000


我们来大致分析一下此段代码,main()方法中实例化ThreadTest并启动该线程,然后调用该线程的一个方法(secondMethod()),因为在主线程中调用方法,所以调用的普通方法secondMethod())会先被执行(但并不是普通方法执行完毕该对象的线程方法才执行,普通方法执行过程中,该线程的方法也会被执行,他们是交替执行的,只是在主线程的普通方法会先被执行而已),所以程序运行时会先执行secondMethod(),而secondMethod()方法代码片段中有synchronized block,因此secondMethod方法被执行后,该方法会占有该对象机锁导致该对象的线程方法一直处于阻塞状态,不能执行,直到secondeMethod释放锁;
使用Thread.sleep(2000)方法时,因为sleep在阻塞线程的同时,并持有该对象锁,所以该对象的其他同步线程(secondMethod())无法执行,直到synchronized block执行完毕(sleep休眠完毕),secondMethod()方法才可以执行,因此输出结果为number*200+100;
使用this.wait(2000)方法时,secondMethod()方法被执行后也锁定了该对象的机锁,执行到this.wait(2000)时,该方法会休眠2S并释当前持有的锁,此时该线程的同步方法会被执行(因为secondMethod持有的锁,已经被wait()所释放),因此输出的结果为:number+100;

为什么第二个number是22000呢,因为wait后,对number*200了,所以值改变了。


再举个简单的例子:假如有三个线程Thread1、Thread2和Thread3都在等待对象objectA的monitor,此时Thread4拥有对象objectA的monitor,当在Thread4中调用objectA.notify()方法之后,Thread1、Thread2和Thread3只有一个能被唤醒。注意,被唤醒不等于立刻就获取了objectA的monitor。假若在Thread4中调用objectA.notifyAll()方法,则Thread1、Thread2和Thread3三个线程都会被唤醒,至于哪个线程接下来能够获取到objectA的monitor就具体依赖于操作系统的调度了。

  上面尤其要注意一点,一个线程被唤醒不代表立即获取了对象的monitor,只有等调用完notify()或者notifyAll()并退出synchronized块,释放对象锁后,其余线程才可获得锁执行。

下面看一个例子就明白了:

package com.lee.thread;

public class WaitNotify {
	public static Object object = new Object();

	public static void main(String[] args) {
		Thread1 thread1 = new Thread1();
		Thread2 thread2 = new Thread2();
		thread1.start();

		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		thread2.start();
	}

	static class Thread1 extends Thread {
		@Override
		public void run() {
			synchronized (object) {
				try {
					object.wait();
				} catch (InterruptedException e) {
				}
				System.out.println("线程" + Thread.currentThread().getName()
						+ "获取到了锁");
			}
		}
	}

	static class Thread2 extends Thread {
		@Override
		public void run() {
			synchronized (object) {
				object.notify();
				System.out.println("线程" + Thread.currentThread().getName()
						+ "调用了object.notify()");
			}
			System.out.println("线程" + Thread.currentThread().getName() + "释放了锁");
		}
	}
}

结果永远是
线程Thread-1调用了object.notify()
线程Thread-1释放了锁
线程Thread-0获取到了锁


Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,在阻塞队列那一篇博文中就讲述到了,阻塞队列实际上是使用了Condition来模拟线程间协作。

    1、Condition是个接口,基本的方法就是await()和signal()方法;
    2、Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
    3、调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
    Conditon中的await()对应Object的wait();
    Condition中的signal()对应Object的notify();
    Condition中的signalAll()对应Object的notifyAll()。


转自:http://www.cnblogs.com/DreamSea/archive/2012/01/16/2263844.html

Condition实例见:http://www.cnblogs.com/dolphin0520/p/3920385.html

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值