線程主動讓出CPU


如何讓線程主動讓出CPU

由於等待一個鎖的線程只有在獲得這把鎖之后,才能恢復運行,所以讓持有鎖的線程在不再需要鎖的時候及時釋放鎖是很重要的。在以下情況下,持有鎖的線程會釋放鎖:
(1)執行完同步代碼塊,就會釋放鎖。(synchronized執行完畢解鎖)
(2)在執行同步代碼塊的過程中,遇到異常而導致線程終止,鎖也會被釋放。(exception異常)
(3)在執行同步代碼塊的過程中,執行了鎖所屬對象的wait()方法,這個線程會釋放鎖,進入對象的等待池。(wait方法被調用)

除了以上情況以外,只要持有鎖的線程還沒有執行完同步代碼塊,就不會釋放鎖。
在下面情況下,線程是不會釋放鎖的:
(1)執行同步代碼塊的過程中,執行了Thread.sleep()方法,當前線程放棄CPU,開始睡眠,在睡眠中不會釋放鎖。
(2)在執行同步代碼塊的過程中,執行了Thread.yield()方法,當前線程放棄CPU,但不會釋放鎖。
(3)在執行同步代碼塊的過程中,其他線程執行了當前線程對象的suspend()方法,當前線程被暫停,但不會釋放鎖。

 

Thread.sleep();

sleep就是正在執行的線程主動讓出cpu,cpu去執行其他線程,在sleep指定的時間過后,cpu才會回到這個線程上繼續往下執行,如果當前線程進入了同步鎖,sleep方法並不會釋放鎖,即使當前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執行。

在多線程爭用的情況,擁有鎖的線程進行一些耗時操作,會極大降低吞吐量(amdahl定律),如果在同步塊中使用sleep就是一種糟糕的做法,它不會釋放鎖卻阻止其他線程獲得鎖。

Thread.yield();

yeild是個native靜態方法,這個方法是想把自己占有的cpu時間釋放掉,然后和其他線程一起競爭(注意yeild的線程還是有可能爭奪到cpu,注意與sleep區別)。在javadoc中也說明了,yeild是個基本不會用到的方法,一般在debug和test中使用。

Object.wait();

wait會把當前的鎖釋放掉同時阻塞住,讓出CPU;當別的線程調用該 Object 的 notify/notifyAll 之后,有可能得到 CPU,同時重新獲得鎖。

當然同樣的

condition.await();

也會釋放鎖並且讓出CPU;

當然很多競爭鎖失敗的線程最終也會阻塞住,但是這不是主動讓出CPU,不在討論范圍內。

Thread.stop();

太過暴力,不推薦使用,同時會釋放所有鎖。容易導致數據不一致,具體請查看[高並發Java 二] 多線程基礎

Thread.currentThread().suspend();

掛起線程,suspend不會釋放鎖,suspend容易發生死鎖,不推薦使用。原因請查看[高並發Java 二] 多線程基礎

LockSupport.park();

與suspend一樣掛起線程,但是park/unpark不會發生死鎖,原因請查看[高並發Java 五] JDK並發包1

Java中Thread的狀態有:

NEW

RUNNABLE

WAITING:Object.wait(),LockSupport.park()

TIMED_WAITING:Thread.sleep(long),Object.wait(long),LockSupport.parkNanos(long)

BLOCKED:Object.wait()

TERMINATED:Thread.stop()

如何讓線程主動放棄持有的鎖

Object.wait();
condition.await();
Thread.stop();

上面已經說了

當然所有釋放鎖的操作都可以:

reentrantLock.unlock();
semaphore.release();

要注意的是以下操作不會釋放鎖,在上面已經談到了,這里再列舉以下:

Thread.sleep();
Thread.yield();
Thread.currentThread().suspend();
LockSupport.park();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM