java.lang.Thread.sleep()方法和java.lang.Object.wait()方法之间的区别

java.lang.Thread.sleep():

sleep()方法为Thread类定义的静态方法,因此需要通过Thread类调用该方法:

Thread.sleep(1000);

Javadoc对该方法的描述如下:

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.The thread does not lose ownership of any monitors.

调用sleep()方法将会导致当前正在执行线程休眠特定的时间

在Java字节码层面,获取锁的字节码指令为:monitorenter,释放锁的字节码指令为:monitorexit,所以我个人认为doc里的monitors可以理解为对象锁

也就是说,调用sleep()方法后进入休眠状态的线程并不会释放其持有的对象锁

package com.sean;

public class Test implements Runnable {

	@Override
	public void run(){
		this.s();
	}
	
	public synchronized void s(){
		System.out.println(Thread.currentThread().getName()
				+ " get lock.");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()
				+ " release lock.");
	} 
	
public static void main(String[] args){
		Test st = new Test();
		Thread t1 = new Thread(st, "t1");
		Thread t2 = new Thread(st, "t2");
		t1.start();	
		t2.start();
	}
}

执行结果如下(t2虽然已经启动,但是直到t1释放锁后才能开始执行):

t1 get lock.
t1 release lock.
t2 get lock.
t2 release lock.

 

java.lang.Object.wait():

wait()方法是Object类定义的普通方法,因此任何对象都可调用该方法

this.wait(1000);

Javadoc对wait()方法的描述如下:

Causes the current thread to wait until either another thread invokes the java.lang.Object.notify() method or the java.lang.Object.notifyAll() method for this object, or a specified amount of time has elapsed.

The current thread must own this object's monitor.

This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Thread T becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:

  • Some other thread invokes the notify method for this object and thread T happens to bearbitrarily chosen as the thread to be awakened. (参见notify()方法的Javadoc:If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation)
  • Some other thread invokes the notifyAll method for this object.
  • Some other thread interrupts thread T.
  • The specified amount of real time has elapsed, more or less. If timeout is zero, however, then real time is not taken into consideration and the thread simply waits until notified.

The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It then competes in the usual manner with other threads for the right to synchronize on the object; once it has gained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.

A thread can also wake up without being notified, interrupted, or timing out, a so-calledspurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

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

If the current thread is interrupted by any thread before or while it is waiting, then anInterruptedException is thrown. This exception is not thrown until the lock status of this object has been restored as described above.

Note that the wait method, as it places the current thread into the wait set for this object, unlocks only this object; any other objects on which the current thread may be synchronized remain locked while the thread waits. (这点要特别注意)

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways(简单来说就是获取该对象的锁):

  • By executing a synchronized instance method of that object(调用该对象的同步方法).
  • By executing the body of a synchronized statement that synchronizes on the object(进入该对象的同步代码块).
  • For objects of type Class, by executing a synchronized static method of that class(调用该对象的同步静态方法).

Only one thread at a time can own an object's monitor.

wait()方法、notify()方法和notifyAll()方法都需要先获取到对象上的锁后才能调用,否则会报java.lang.IllegalMonitorStateException

当线程调用对象的wait()方法后,线程将进入等待状态并释放其持有的该对象上的锁(线程仍然持有其它对象的锁)

当对象的notify()方法、notifyAll()方法被调用,或者线程被中断,或者线程等待了wait()方法指定的等待时间(如果为wait(0),则只有对象的notify()方法或notifyAll()方法被调用后线程才会退出等待状态)后,线程将退出等待状态,并和其它线程公平的竞争对象上的锁,一旦线程成功获取到对象锁,线程将从wait()方法调用返回,对象的同步状态和线程的同步状态将和wait()方法调时一样

package com.sean;
public class Test1 implements Runnable {
	private Object lock;
	
	public Test1(Object lock){
		this.lock = lock;
	}

	@Override
	public void run(){
		synchronized(lock){
			System.out.println(Thread.currentThread().getName()
					+ " get lock.");
			try {
				lock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()
					+ " release lock.");
		}
	}
}
package com.sean;

public class Test2 implements Runnable {
	private Object lock;
	
	public Test2(Object lock){
		this.lock = lock;
	}

	@Override
	public void run() {
		try {
			Thread.sleep(2*1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		synchronized(lock){
			System.out.println(Thread.currentThread().getName()
					+ " get lock.");
			lock.notifyAll();
			System.out.println(Thread.currentThread().getName()
					+ " release lock.");
		}
		synchronized(lock){
			System.out.println(Thread.currentThread().getName()
					+ " get lock.");
			System.out.println(Thread.currentThread().getName()
					+ " release lock.");
		}
	}
	
	public static void main(String[] args){
		Object lock = new Object();
		Thread t1 = new Thread(new Test1(lock), "t1");
		Thread t2 = new Thread(new Test2(lock), "t2");
		t1.start();
		t2.start();
	}
}

执行结果如下:

t1 get lock.
t2 get lock.
t2 release lock.
t2 get lock.
t2 release lock.
t1 release lock.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值