小編這次要給大家分享的是詳解Java如何實(shí)現(xiàn)線程同步,文章內(nèi)容豐富,感興趣的小伙伴可以來(lái)了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。
創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站制作、網(wǎng)站建設(shè)與策劃設(shè)計(jì),新建網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:新建等地區(qū)。新建做網(wǎng)站價(jià)格咨詢:028-86922220
一、概述
無(wú)論是什么語(yǔ)言,在多線程編程中,常常會(huì)遇到多個(gè)線同時(shí)操作程某個(gè)變量(讀/寫),如果讀/寫不同步,則會(huì)造成不符合預(yù)期的結(jié)果。
例如:線程A和線程B并發(fā)運(yùn)行,都操作變量X,若線程A對(duì)變量X進(jìn)行賦上一個(gè)新值,線程B仍然使用變量X之前的值,很明顯線程B使用的X不是我們想要的值了。
Java提供了三種機(jī)制,解決上述問(wèn)題,實(shí)現(xiàn)線程同步:
同步代碼塊
synchronized(鎖對(duì)象){ // 這里添加受保護(hù)的數(shù)據(jù)操作 }
同步方法
靜態(tài)同步方法:synchronized修飾的靜態(tài)方法,它的同步鎖是當(dāng)前方法所在類的字節(jié)碼對(duì)象
public static synchronized void staticMethod(){ }
非靜態(tài)同步方法:synchronized修飾的非靜態(tài)方法,它的同步鎖即為this
public synchronize void method(){ }
鎖機(jī)制
// 以可重入鎖舉例
Lock lock = new ReentrantLock(/*fail*/);
// fail:
// true表示使用公平鎖,即線程等待拿到鎖的時(shí)間越久,越容易拿到鎖
// false表示使用非公平鎖,線程拿到鎖全靠運(yùn)氣。。。cpu時(shí)間片輪到哪個(gè)線程,哪個(gè)線程就能獲取鎖
lock.lock();
// 這里添加受保護(hù)的數(shù)據(jù)操作
lock.unlock();
個(gè)人理解:其實(shí)無(wú)論哪種機(jī)制實(shí)現(xiàn)線程同步,本質(zhì)上都是加鎖->操作數(shù)據(jù)->解鎖的過(guò)程。同步代碼塊是針對(duì){}中,同步方法是針對(duì)整個(gè)方法。其ReentrantLock類提供的lock和unlock和C++的std::mutex提供lock和unlock類似
二、測(cè)試用例
同步代碼塊測(cè)試類
package base.synchronize; public class SynchronizeBlock implements Runnable { private int num = 100; @Override public void run() { while (num > 1) { synchronized (this) { // 同步代碼塊,只有拿到鎖,才有cpu執(zhí)行權(quán) System.out.println("Thread ID:" + Thread.currentThread().getId() + "---num:" + num); num--; } } System.out.println("Thread ID:" + Thread.currentThread().getId() + " exit"); } }
同步方法測(cè)試類
package base.synchronize; public class SynchronizeMethod implements Runnable { private int num = 100; public static int staticNum = 100; boolean useStaticMethod; public SynchronizeMethod(boolean useStaticMethodToTest) { this.useStaticMethod = useStaticMethodToTest; } // 對(duì)于非靜態(tài)方法,同步鎖對(duì)象即this public synchronized void method() { System.out.println("Thread ID:" + Thread.currentThread().getId() + "---num:" + num); num--; } // 對(duì)于靜態(tài)方法,同步鎖對(duì)象是當(dāng)前方法所在類的字節(jié)碼對(duì)象 public synchronized static void staticMethod() { System.out.println("Static Method Thread ID:" + Thread.currentThread().getId() + "---num:" + staticNum); staticNum--; } @Override public void run() { if (useStaticMethod) { // 測(cè)試靜態(tài)同步方法 while (staticNum > 1) { staticMethod(); } }else{ // 測(cè)試非靜態(tài)同步方法 while (num > 1){ method(); } } System.out.println("Thread ID:" + Thread.currentThread().getId() + " exit"); } }
ReentrantLock測(cè)試類
package base.synchronize; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class SynchronizeLock implements Runnable { private Lock lock = null; private int num = 100; public SynchronizeLock(boolean fair){ lock = new ReentrantLock(fair); // 可重入鎖 } @Override public void run() { while (num > 1) { try { lock.lock(); System.out.println("Thread ID:" + Thread.currentThread().getId() + "---num:" + num); num--; } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } System.out.println("Thread ID:" + Thread.currentThread().getId() + " exit"); } }
測(cè)試三種機(jī)制的Demo
package base.synchronize; public class Demo { public static void main(String[] args) { synchronizeBlockTest(); // 同步代碼塊 synchronizeMethodTest(); // 同步非靜態(tài)方法 synchronizeStaticMethodTest(); // 同步靜態(tài)方法 synchronizeLockTest(); // 可重入鎖機(jī)制 } public static void synchronizeBlockTest(){ Runnable run = new SynchronizeBlock(); for(int i = 0; i < 3; i++){ new Thread(run).start(); } } public static void synchronizeMethodTest(){ Runnable run = new SynchronizeMethod(false); for(int i = 0; i < 3; i++){ new Thread(run).start(); } } public static void synchronizeStaticMethodTest() { Runnable run = new SynchronizeMethod(true); for(int i = 0; i < 3; i++){ new Thread(run).start(); } } public static void synchronizeLockTest(){ Runnable run = new SynchronizeLock(false); // true:使用公平鎖 false:使用非公平鎖 for(int i = 0; i < 3; i++){ new Thread(run).start(); } } }
無(wú)論哪種機(jī)制,都得到預(yù)期的效果,打印100-0
看完這篇關(guān)于詳解Java如何實(shí)現(xiàn)線程同步的文章,如果覺(jué)得文章內(nèi)容寫得不錯(cuò)的話,可以把它分享出去給更多人看到。