Thread.sleep 與 object.wait()區別
共同點:
1. 兩個方法都會導致線程阻塞
不同點:
1. sleep在阻塞的時候,如果擁有鎖,線程不會釋放鎖;而wait會釋放鎖
3. wait必須在同步代碼塊內使用;sleep則不必
notify(),notifyAll()
共同點:
1. 喚醒wait線程
不同點:
1. notify只喚醒一個wait線程
2. notifyAll喚醒所有wait線程
public class WaitUse {
public static void main(String[] args) {
new Thread(new Thread1()).start();
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable{
@Override
public void run(){
synchronized (WaitUse.class) {
System.out.println("enter thread1...");
System.out.println("thread1 is waiting...");
try {
//調用wait()方法,線程會放棄對象鎖(WaitUse.class)
WaitUse.class.wait();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread1 is going on ....");
System.out.println("thread1 is over!!!");
}
}
}
private static class Thread2 implements Runnable{
@Override
public void run(){
synchronized (WaitUse.class) {
System.out.println("enter thread2....");
System.out.println("thread2 is waiting....");
System.out.println("notify()");
//對此對象調用notify()方法後,對應調用該對象wait()方法的線程就會進入等待獲取鎖的狀態(這裏是Thread1)
//需要注意的是,如果有多個線程調用了wait方法,那notify()只會喚醒其中的一個線程。要想喚醒所有線程,需要調用notifyAll()
WaitUse.class.notify();
//==================
//區別
//如果我們把代碼:WaitUse.class.notify();給註釋掉,即WaitUse.class調用了wait()方法,但是沒有調用notify()
//方法,則線程永遠處於掛起狀態。
try {
//sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,當指定的時間到了又會自動恢復運行狀態。
//在調用sleep()方法的過程中,線程不會釋放對象鎖。
//Thread.sleep(5000);//方式一:不會釋放鎖,所以只有Thread2 sleep 結束,然後執行完synchronized塊,
// Thread1才能獲取到鎖,不然都會一直處於阻塞狀態
WaitUse.class.wait();//方式二:會釋放鎖
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread2 is going on....");
System.out.println("thread2 is over!!!");
}
}
}
}
join()
源碼:
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {//獲取對象鎖,也就是this
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {//如果子線程已經啓動,並且還沒有運行結束,則調用wait方法,使得當前線程進入等待狀態(會釋放對象鎖this)
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
例子:
public class JoinUse extends Thread {
public static int a = 0;
public void run() {
for (int k = 0; k < 5; k++) {
a = a + 1;
}
}
public static void main(String[] args) throws Exception {
Thread t = new JoinUse();
t.start();
t.join(); //使得當前線程進入等待狀態,這裏是主線程。知道子線程執行完畢,主線程纔會結束等待
System.out.println(a);
}
}