Java中怎么利用多線程解決資源競爭,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
創(chuàng)新互聯(lián)主營潮陽網(wǎng)站建設的網(wǎng)絡公司,主營網(wǎng)站建設方案,成都APP應用開發(fā),潮陽h5小程序定制開發(fā)搭建,潮陽網(wǎng)站營銷推廣歡迎潮陽等地區(qū)企業(yè)咨詢
一、c#下的幾種鎖的運用方式
1、臨界區(qū),通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數(shù)據(jù)訪問。
private static object obj = new object(); private static int lockInt; private static void LockIntAdd() { for (var i = 0; i < runTimes; i++) { lock (obj) { lockInt++; } } }
你沒看錯,c#中的lock語法就是臨界區(qū)(Monitor)的一個語法糖,這大概是90%以上的.net程序員首先想到的鎖,不過大部分人都只是知道
有這么個語法,不知道其實是以臨界區(qū)的方式處理資源競爭。
2、互斥量,為協(xié)調(diào)共同對一個共享資源的單獨訪問而設計的。
c#中有一個Mutex類,就在System.Threading命名空間下,Mutex其實就是互斥量,互斥量不單單能處理多線程之間的資源競爭,還能處理
進程之間的資源競爭,功能是比較強大的,但是開銷也很大,性能比較低。
private static Mutex mutex = new Mutex(); private static int mutexInt; private static void MutexIntAdd() { for (var i = 0; i < runTimes; i++) { mutex.WaitOne(); mutexInt++; mutex.ReleaseMutex(); } }
3、信號量,為控制一個具有有限數(shù)量用戶資源而設計。
private static Semaphore sema = new Semaphore(1, 1); private static int semaphoreInt; private static void SemaphoreIntAdd() { for (var i = 0; i < runTimes; i++) { sema.WaitOne(); semaphoreInt++; sema.Release(); } }
4、事 件:用來通知線程有一些事件已發(fā)生,從而啟動后繼任務的開始。
public static AutoResetEvent autoResetEvent = new AutoResetEvent(true); private static int autoResetEventInt; private static void AutoResetEventIntAdd() { for (var i = 0; i < runTimes; i++) { if (autoResetEvent.WaitOne()) { autoResetEventInt++; autoResetEvent.Set(); } } }
5、讀寫鎖,這種鎖允許在有其他程序正在寫的情況下讀取資源,所以如果資源允許臟讀,用這個比較合適
private static ReaderWriterLockSlim LockSlim = new ReaderWriterLockSlim(); private static int lockSlimInt; private static void LockSlimIntAdd() { for (var i = 0; i < runTimes; i++) { LockSlim.EnterWriteLock(); lockSlimInt++; LockSlim.ExitWriteLock(); } }
6、原子鎖,通過原子操作Interlocked.CompareExchange實現(xiàn)“無鎖”競爭
private static int isLock; private static int ceInt; private static void CEIntAdd() { //long tmp = 0; for (var i = 0; i < runTimes; i++) { while (Interlocked.CompareExchange(ref isLock, 1, 0) == 1) { Thread.Sleep(1); } ceInt++; Interlocked.Exchange(ref isLock, 0); } }
7、原子性操作,這是一種特例,野外原子性操作本身天生線程安全,所以無需加鎖
private static int atomicInt; private static void AtomicIntAdd() { for (var i = 0; i < runTimes; i++) { Interlocked.Increment(ref atomicInt); } }
8、不加鎖,如果不加鎖,那多線程下運行結(jié)果肯定是錯的,這里貼上來比較一下性能
private static int noLockInt; private static void NoLockIntAdd() { for (var i = 0; i < runTimes; i++) { noLockInt++; } }
二、性能測試
1、測試代碼,執(zhí)行1000,10000,100000,1000000次
private static void Run() { var stopwatch = new Stopwatch(); var taskList = new Task[loopTimes]; // 多線程 Console.WriteLine(); Console.WriteLine($" 線程數(shù):{loopTimes}"); Console.WriteLine($" 執(zhí)行次數(shù):{runTimes}"); Console.WriteLine($" 校驗值應等于:{runTimes * loopTimes}"); // AtomicIntAdd stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { AtomicIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("AtomicIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{atomicInt}"); // CEIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { CEIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("CEIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{ceInt}"); // LockIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { LockIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("LockIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{lockInt}"); // MutexIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { MutexIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("MutexIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{mutexInt}"); // LockSlimIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { LockSlimIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("LockSlimIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{lockSlimInt}"); // SemaphoreIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { SemaphoreIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("SemaphoreIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{semaphoreInt}"); // AutoResetEventIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { AutoResetEventIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("AutoResetEventIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{autoResetEventInt}"); // NoLockIntAdd taskList = new Task[loopTimes]; stopwatch.Restart(); for (var i = 0; i < loopTimes; i++) { taskList[i] = Task.Factory.StartNew(() => { NoLockIntAdd(); }); } Task.WaitAll(taskList); Console.WriteLine($"{GetFormat("NoLockIntAdd")}, 總耗時:{stopwatch.ElapsedMilliseconds}毫秒, 校驗值:{noLockInt}"); Console.WriteLine(); }
2、線程:10
3、線程:50
三、總結(jié)
1)在各種測試中,不加鎖肯定是最快的,所以盡量避免資源競爭導致加鎖運行
2)在多線程中Interlocked.CompareExchange始終表現(xiàn)出優(yōu)越的性能,排在第二位
3)第三位lock,臨界區(qū)也表現(xiàn)出很好的性能,所以在別人說lock性能低的時候請反駁他
4)第四位是原子性變量(Atomic)操作,不過目前只支持變量的自增自減,適用性不強
5)第五位讀寫鎖(ReaderWriterLockSlim)表現(xiàn)也還可以,并且支持無所讀,實用性還是比較好的
6)剩下的信號量、事件、互斥量,這三種性能最差,當然他們有各自的適用范圍,只是在處理資源競爭這方面表現(xiàn)不好
看完上述內(nèi)容,你們掌握Java中怎么利用多線程解決資源競爭的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
新聞標題:Java中怎么利用多線程解決資源競爭
本文URL:http://aaarwkj.com/article28/iipsjp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、做網(wǎng)站、網(wǎng)站導航、網(wǎng)站收錄、響應式網(wǎng)站、云服務器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)