sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态。可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。
wait()方法需要和notify()及notifyAll()两个方法一起介绍,这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用,也就是说,调用wait(),notify()和notifyAll()的任务在调用这些方法前必须拥有对象的锁。注意,它们都是Object类的方法,而不是Thread类的方法。 除了使用notify()和notifyAll()方法,还可以使用带毫秒参数的wait(long timeout)方法,效果是在延迟timeout毫秒后,被暂停的线程将被恢复到锁标志等待池。 wait(),notify()及notifyAll()只能在synchronized语句中使用,但是如果使用的是ReenTrantLock实现同步,该如何达到这三个方法的效果呢?解决方法是使用ReenTrantLock.newCondition()获取一个Condition类对象,然后Condition的await(),signal()以及signalAll()分别对应上面的三个方法。
yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。
join()方法会使当前线程等待调用join()方法的线程结束后才能继续执行.
这两个方法来自不同的类,sleep是Thread类的方法,而wait是Object类的方法
//Object.java
public class Object {
public native int hashCode()
public boolean equals(Object obj)
public String toString()
public final native void notify();
public final native void notifyAll();
public final void wait()
}
//Thread
class Thread implements Runnable {
public static native void yield();
public static native void sleep(long millis);
...
}
执行sleep方法后不会释放锁,而执行wait方法后会释放锁.
package com.hit.learn.concurrencyinaction;
public class TestD {
public static void main(String[] args) {
new Thread(new Thread1()).start();
try {
Thread.sleep(1000);
System.out.println("main thread is work:1s, Thread1 is run and hold lock!");
} catch (Exception e) {
e.printStackTrace();
}
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable {
@Override
public void run() {
System.out.println("Thread1 started!");
synchronized (TestD.class) {
try {
Thread.sleep(5000);
//TestD.class.wait();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread1 is over!!!");
}
}
}
private static class Thread2 implements Runnable {
@Override
public void run() {
System.out.println("Thread2 started!");
synchronized (TestD.class) {
System.out.println("Thread2 hold Lock");
//TestD.class.notify();
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread2 is going on....");
System.out.println("thread2 is over!!!");
}
}
}
}
执行结果如下:
Thread1 started!
main thread is work:1s, Thread1 is run and hold lock!
Thread2 started!
thread1 is over!!!
Thread2 hold Lock
thread2 is going on....
thread2 is over!!!
Thread1先启动,sleep了5s.在这期间启动Thread2 是不能获得锁的,会在Thread2中的 synchronized (TestD.class) {} Block住,等待Thread1释放掉lock之后,才能获得锁继续执行.
package com.hit.learn.concurrencyinaction;
public class TestD {
public static void main(String[] args) {
new Thread(new Thread1()).start();
try {
Thread.sleep(1000);
System.out.println("main thread is work:1s, Thread1 is run and hold lock!");
} catch (Exception e) {
e.printStackTrace();
}
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable {
@Override
public void run() {
System.out.println("Thread1 started!");
synchronized (TestD.class) {
try {
//Thread.sleep(5000);
TestD.class.wait();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread1 is over!!!");
}
}
}
private static class Thread2 implements Runnable {
@Override
public void run() {
System.out.println("Thread2 started!");
synchronized (TestD.class) {
System.out.println("Thread2 hold Lock");
TestD.class.notify();
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread2 is going on....");
System.out.println("thread2 is over!!!");
}
}
}
}
执行结果如下:
Thread1 started!
main thread is work:1s, Thread1 is run and hold lock!
Thread2 started!
Thread2 hold Lock
thread2 is going on....
thread2 is over!!!
thread1 is over!!!
Thread1先启动,wait()了5s.在这期间启动Thread2 是不能获得锁的,不会在Thread2中的 synchronized (TestD.class) {} Block住,notify()之后可以继续执行.
wait,notify和notifyAll只能在同步方法或同步代码块中调用,而sleep可以在任何地方调用。
private static class Thread1 implements Runnable {
@Override
public void run() {
System.out.println("Thread1 started!");
try {
TestD.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
先说两个概念:锁池和等待池
然后再来说notify和notifyAll的区别:
综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了。