[Java] What’s the Difference between wait() and sleep()?

下面是從 Android Dalvik 拿來的 code,參考看看他的實作內容,

1329 void dvmThreadSleep(u8 msec, u4 nsec) 
1330 {
1331 Thread* self = dvmThreadSelf();
1332 Monitor* mon = gDvm.threadSleepMon;
1333
1334 /* sleep(0,0) wakes up immediately, wait(0,0) means wait forever; adjust */
1335 if (msec == 0 && nsec == 0)
1336 nsec++;
1337
1338 lockMonitor(self, mon);
1339 waitMonitor(self, mon, msec, nsec, true);
1340 unlockMonitor(self, mon);
1341 }


Sleep 是個 Thread Class static method,從實作上來看,他使用的是 global monitor,所以在操作上,如果在一個 synchronized 區塊中,有一個 Thread 使用 Sleep method,因為他還是握有 monitor,沒有unlock此區塊,所以就會造成,即使此 Thread 已經 Sleep,但是其他的 Thread 還是無法執行這個區塊。

而在waitnotify部分,比較簡單來說,wait 等待某個Threadnotify 他,可以用來實作 Consumer-Producer 的應用。
所以狀況會是 Thread A (Consumer) Queue 裡面沒有東西時,就跑去 wait,直到有個 Thread B (Producer) 產生出新產品放到 Queue 後,Thread B notifyThread A,告訴他有新產品放進去 Queue 了,此時,Thread A 就會去作相對應的動作了。

1229 void dvmObjectWait(Thread* self, Object *obj, s8 msec, s4 nsec,
1230 bool interruptShouldThrow)
1231 {
1232 Monitor* mon;
1233 u4 thin = obj->lock;
1234
……
1245
1246 /* This thread holds the lock. We need to fatten the lock
1247 * so 'self' can block on it. Don't update the object lock
1248 * field yet, because 'self' needs to acquire the lock before
1249 * any other thread gets a chance.
1250 */
1251 inflateMonitor(self, obj);
1252 LOG_THIN("(%d) lock %p fattened by wait() to count %d",
1253 self->threadId, &obj->lock, mon->lockCount);
1254 }
1255 mon = LW_MONITOR(obj->lock);
1256 waitMonitor(self, mon, msec, nsec, interruptShouldThrow);
1257 }

因為希望同時有多個 Thread 可以使用某個 object,所以在 wait 實作內,就會 create 一個新的 monitor Thread ,如下面這段 code

944 static void inflateMonitor(Thread *self, Object *obj) 
945 {
946 Monitor *mon;
947 u4 thin;
……
953 /* Allocate and acquire a new monitor. */
954 mon = dvmCreateMonitor(obj);
955 lockMonitor(self, mon);
……
963 }

然後每個在等待的 Thread 都會被加到 wait set 裡面,當有個 Thread notify 時,就會去找到在 wait set 裡面的第一個 Thread (這點要看實作面,不一定每個Java VM都這樣)

881 static void notifyMonitor(Thread* self, Monitor* mon)
881 static void notifyMonitor(Thread* self, Monitor* mon)
882 {
883 Thread* thread;
884
……
894 /// Signal the first waiting thread in the wait set.
895 while (mon->waitSet != NULL) {
896 thread = mon->waitSet;
897 mon->waitSet = thread->waitNext;
898 thread->waitNext = NULL;
899 dvmLockMutex(&thread->waitMutex);
900 /// Check to see if the thread is still waiting.
901 if (thread->waitMonitor != NULL) {
902 pthread_cond_signal(&thread->waitCond);
903 dvmUnlockMutex(&thread->waitMutex);
904 return;
905 }
906 dvmUnlockMutex(&thread->waitMutex);
907 }
908 }

結論是,想要多個 Thread 同時處理某個 object 時,可以採取 wait & notify 方式,在某個 Thread 完成 Thread 的需求時,便可以 notify 那些 Thread,把他們叫起來完成需求。
如果只是單純要一個 Thread 停下來一段時間,可以使用 Thread Class Sleep method

One comment

發佈留言