国产成人精品亚洲777人妖,欧美日韩精品一区视频,最新亚洲国产,国产乱码精品一区二区亚洲

您的位置:首頁技術(shù)文章
文章詳情頁

Java中的多線程一定就快嗎?

瀏覽:82日期:2022-08-25 11:05:53

并發(fā)編程與多線程編程

要了解并發(fā)編程,首先要懂得與并行這個(gè)概念進(jìn)行區(qū)分。并行是指兩個(gè)事件同時(shí)進(jìn)行,并發(fā)是CPU切換速度快,看起來像是每個(gè)任務(wù)同時(shí)進(jìn)行一樣。多線程是實(shí)現(xiàn)并發(fā)編程的一種方式,假設(shè)一個(gè)場景,在廣州地鐵高峰時(shí)段,一群人涌進(jìn)地鐵里,在不同的閘機(jī)口刷卡進(jìn)去。在這個(gè)場景里,進(jìn)地鐵就是任務(wù),每個(gè)人可以看出是并發(fā)的,而多個(gè)刷卡閘機(jī)口就是多線程。

  并發(fā)編程的本質(zhì)目的是為了充分利用CPU,讓程序運(yùn)行得更快。然而,并不是啟動(dòng)更多的線程就能讓程序最大限度地并發(fā)執(zhí)行。在進(jìn)行并發(fā)編程時(shí),如果希望通過多線程執(zhí)行任務(wù)讓程序運(yùn)行得更快,會(huì)面臨非常多的挑戰(zhàn)。比如上下文切換的問題、死鎖的問題,以及受限于硬件和軟件的資源限制問題,下面就來嘮嗑嘮嗑這些因素。

上下文切換

原理分析

正如上面所言,并發(fā)與并行最大的區(qū)別就是,并發(fā)只是看起來像是并行。實(shí)際上是,CPU通過給每個(gè)線程分配時(shí)間來執(zhí)行這個(gè)線程的程序,只是這個(gè)時(shí)間非常短,通常是幾十毫秒,我們根本無法觀察到變化,感覺它們都是同時(shí)執(zhí)行的一樣。

  CPU通過時(shí)間片分配算法來循環(huán)執(zhí)行任務(wù),當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后會(huì)切換到下一個(gè)任務(wù)。但是,在切換前會(huì)保存上一個(gè)任務(wù)的狀態(tài),以便下次切換回這個(gè)任務(wù)時(shí),可以再加載這個(gè)任務(wù)的狀態(tài)。所以任務(wù)從保存到再加載的過程就是一次上下文切換。因此,不難得知,上下文切換需要耗費(fèi)不少時(shí)間。

  再來假設(shè)一個(gè)場景,一個(gè)人去火車站買票,買票的窗口有十來個(gè)那么多。買票的人并不知道哪個(gè)窗口可以買到票,只能挨個(gè)地問,最后終于在最后一個(gè)窗口買到了。這個(gè)場景,看似買票的過程很長,其實(shí)大部分時(shí)間都在切換窗口上,這也就是上下文切換的問題所在。因此,并非線程數(shù)多就一定執(zhí)行得快,要選擇與任務(wù)相適應(yīng)的線程數(shù)才是最佳方案。

測試代碼

package Concurrency;/** * @author RuiMing Lin * @date 2020-03-28 12:19 */public class Demo1 { public static void main(String[] args) { System.out.println('萬級(jí)循環(huán):'); concurrency(10000); serial(10000); System.out.println('--------------------------華麗分隔符--------------------------------'); System.out.println('十萬級(jí)循環(huán):'); concurrency(100000); serial(100000); System.out.println('--------------------------華麗分隔符--------------------------------'); System.out.println('百萬級(jí)循環(huán):'); concurrency(1000000); serial(1000000); System.out.println('--------------------------華麗分隔符--------------------------------'); System.out.println('千萬級(jí)循環(huán):'); concurrency(10000000); serial(10000000); System.out.println('--------------------------華麗分隔符--------------------------------'); System.out.println('億級(jí)循環(huán):'); concurrency(100000000); serial(100000000); } private static void concurrency(long count){ // 開啟三個(gè)線程執(zhí)行三個(gè)循環(huán) long start = System.currentTimeMillis(); new Thread(new Runnable() { @Override public void run() {int a = 0;for (long i = 0; i < count; i++) { a++;} } }).start(); new Thread(new Runnable() { @Override public void run() {int b = 0;for (long i = 0; i < count; i++) { b++;} } }).start(); new Thread(new Runnable() { @Override public void run() {int c = 0;for (long i = 0; i < count; i++) { c++;} } }).start(); long end = System.currentTimeMillis(); long time = end - start; System.out.println('并行執(zhí)行花費(fèi)時(shí)間為:' + time + 'ms'); } private static void serial(long count){ // 三個(gè)循環(huán)順序執(zhí)行 long start = System.currentTimeMillis(); int a = 0; int b = 0; int c = 0; for (int i = 0; i < count; i++) { a++; } for (int i = 0; i < count; i++) { b++; } for (int i = 0; i < count; i++) { c++; } long end = System.currentTimeMillis(); long time = end - start; System.out.println('串行執(zhí)行花費(fèi)時(shí)間為:' + time + 'ms'); }}

結(jié)果輸出:

萬級(jí)循環(huán): 并行執(zhí)行花費(fèi)時(shí)間為:4ms 串行執(zhí)行花費(fèi)時(shí)間為:1ms

--------------------------華麗分隔符--------------------------------

十萬級(jí)循環(huán): 并行執(zhí)行花費(fèi)時(shí)間為:1ms 串行執(zhí)行花費(fèi)時(shí)間為:4ms

--------------------------華麗分隔符--------------------------------

百萬級(jí)循環(huán): 并行執(zhí)行花費(fèi)時(shí)間為:1ms 串行執(zhí)行花費(fèi)時(shí)間為:10ms

--------------------------華麗分隔符--------------------------------

千萬級(jí)循環(huán): 并行執(zhí)行花費(fèi)時(shí)間為:1ms 串行執(zhí)行花費(fèi)時(shí)間為:36ms

--------------------------華麗分隔符--------------------------------

億級(jí)循環(huán): 并行執(zhí)行花費(fèi)時(shí)間為:1ms 串行執(zhí)行花費(fèi)時(shí)間為:357ms

分析結(jié)果:

當(dāng)數(shù)量級(jí)在萬級(jí)時(shí),串行是比并發(fā)要快的,當(dāng)數(shù)量級(jí)來到十萬以后,串行便顯得力不從心了。所以,可以認(rèn)為當(dāng)程序執(zhí)行量不夠大時(shí),是沒必要開啟多線程的。

如何減少上下文切換

減少上下文切換的方法有無鎖并發(fā)編程、CAS算法、使用最少線程和使用協(xié)程。

無鎖并發(fā)編程。多線程競爭鎖時(shí),會(huì)引起上下文切換,所以多線程處理數(shù)據(jù)時(shí),可以用一些辦法來避免使用鎖,如將數(shù)據(jù)的ID按照Hash算法取模分段,不同的線程處理不同段的數(shù)據(jù)。 CAS算法。Java的Atomic包使用CAS算法來更新數(shù)據(jù),而不需要加鎖。 使用最少線程。避免創(chuàng)建不需要的線程,比如任務(wù)很少,但是創(chuàng)建了很多線程來處理,這樣會(huì)造成大量線程都處于等待狀態(tài)。 協(xié)程:在單線程里實(shí)現(xiàn)多任務(wù)的調(diào)度,并在單線程里維持多個(gè)任務(wù)間的切換。

死鎖

原理分析

 死鎖,是指多個(gè)線程在運(yùn)行過程中因爭奪相同資源而造成的一種僵局,當(dāng)進(jìn)程處于這種僵持狀態(tài)時(shí),它們都將無法再向前推進(jìn),此時(shí)程序就處于癱瘓狀態(tài),無法執(zhí)行。 通常情況下,是多個(gè)線程共同競爭同一把鎖對(duì)象,而其中一個(gè)線程獲得鎖之后發(fā)生異常等未來得及釋放鎖,導(dǎo)致其它線程一直在等待,無法運(yùn)行。

測試代碼

package Concurrency;/** * @author RuiMing Lin * @date 2020-03-28 13:14 */public class Demo2 { private static String str1 = 'A'; private static String str2 = 'B'; public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() {synchronized (str1){ System.out.println('第一個(gè)線程獲得str1'); try { Thread.currentThread().sleep(2000); }catch (InterruptedException e){ e.printStackTrace(); } synchronized (str2){ System.out.println('第一個(gè)線程獲得str2'); }} } }).start(); new Thread(new Runnable() { @Override public void run() {synchronized (str2){ System.out.println('第二個(gè)線程獲得str2'); try { Thread.currentThread().sleep(2000); }catch (InterruptedException e){ e.printStackTrace(); } synchronized (str1){ System.out.println('第二個(gè)線程獲得str1'); }} } }).start(); }}

結(jié)果輸出:

Java中的多線程一定就快嗎?

如何解決死鎖

避免一個(gè)線程同時(shí)獲取多個(gè)鎖。 避免一個(gè)線程在鎖內(nèi)同時(shí)占用多個(gè)資源,盡量保證每個(gè)鎖只占用一個(gè)資源。 嘗試使用定時(shí)鎖,使用lock.tryLock(timeout)來替代使用內(nèi)部鎖機(jī)制。 對(duì)于數(shù)據(jù)庫鎖,加鎖和解鎖必須在一個(gè)數(shù)據(jù)庫連接里,否則會(huì)出現(xiàn)解鎖失敗的情況。

總結(jié)

并發(fā)程序并不是簡單的程序,編寫的時(shí)候應(yīng)該嚴(yán)謹(jǐn)一些。復(fù)雜的代碼容易引起死鎖,因此,建議多使用JDK并發(fā)包提供的并發(fā)容器和工具類來解決并發(fā)問題。同時(shí),也要注重新能上的問題,既要考慮到程序執(zhí)行任務(wù)量,也要考慮CPU性能等等,不要一昧地增加線程數(shù)。

以上就是Java中的多線程一定就快嗎?的詳細(xì)內(nèi)容,更多關(guān)于Java 多線程的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 理塘县| 通州市| 平阴县| 尤溪县| 牙克石市| 沁阳市| 肥城市| 新蔡县| 故城县| 宣威市| 阿坝县| 安岳县| 伊春市| 定州市| 荥经县| 福安市| 青冈县| 天柱县| 毕节市| 呼和浩特市| 南康市| 夹江县| 舒兰市| 长海县| 巴林左旗| 义马市| 神木县| 肃宁县| 汤阴县| 鄯善县| 晴隆县| 宾川县| 自贡市| 察雅县| 安义县| 昌都县| 南康市| 大港区| 镶黄旗| 桦南县| 泰宁县|