日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并发编程快速入门

發(fā)布時間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并发编程快速入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1、線程與進程的區(qū)別

進程是所有線程的集合,每一個線程是進程中的一條執(zhí)行路徑。

比方:通過查看 windows 任務管理器中的列表,我們可以把運行在內(nèi)存中的 exe 文件理解成進程,進程是受操作系統(tǒng)管理的基本運行單元。

2、為什么要使用多線程?

主要體現(xiàn)在多線程提高程序效率,但是需要注意,并不是使用了多線程就一定能提升性能,有的情況反而會降低性能。

多線程應用場景:

2.1、避免阻塞

我們知道,在我們單線程中,代碼是順序執(zhí)行的,如果前面的操作發(fā)生了阻塞,那么就會影響到后面的操作,這時候可以采用多線程,可以理解成異步調(diào)用;其實前端里的 ajax 就是一個很好地例子,默認 ajax 是開啟異步的,調(diào)用時瀏覽器會啟一個新的線程,不阻塞當前頁面的正常操作;

2.2、避免CPU空轉(zhuǎn)

以http server為例,如果只用單線程響應HTTP請求,即處理完一條請求,再處理下一條請求的話,CPU會存在大量的閑置時間;

因為處理一條請求,經(jīng)常涉及到RPC、數(shù)據(jù)庫訪問、磁盤IO等操作,這些操作的速度比CPU慢很多,而在等待這些響應的時候,CPU卻不能去處理新的請求,因此http server的性能就很差;

所以很多web容器,都采用對每個請求創(chuàng)建新線程來響應的方式實現(xiàn),這樣在等待請求A的IO操作的等待時間里,就可以去繼續(xù)處理請求B,對并發(fā)的響應性就好了很多 。

3、多線程常見的兩種創(chuàng)建方式

3.1、繼承Thread類,重寫run方法
/*** author: niceyoo* blog: https://cnblogs.com/niceyoo* desc:*/ public class ThreadDemo {public static void main(String[] args) {System.out.println("-----多線程創(chuàng)建開始-----");/* 1.創(chuàng)建一個線程*/CreateThread createThread = new CreateThread();/* 2.開始執(zhí)行線程 注意 開啟線程不是調(diào)用run方法,而是start方法*/System.out.println("-----多線程創(chuàng)建啟動-----");createThread.start();System.out.println("-----多線程創(chuàng)建結(jié)束-----");} }class CreateThread extends Thread {/*run方法中編寫 多線程需要執(zhí)行的代碼*/@Overridepublic void run() {for (int i = 0; i< 10; i++) {System.out.println("i:" + i);}} }

打印結(jié)果:

-----多線程創(chuàng)建開始----- -----多線程創(chuàng)建啟動----- -----多線程創(chuàng)建結(jié)束----- i:0 i:1 i:2 i:3 i:4 i:5 i:6 i:7 i:8 i:9

線程調(diào)用 start() 方法后,代碼并沒有從上往下執(zhí)行,而是有一條新的執(zhí)行分支。

注意:畫圖演示多線程不同執(zhí)行路徑。

3.2、實現(xiàn)Runnable接口,重寫run方法
/*** author: niceyoo* blog: https://cnblogs.com/niceyoo* desc:*/ class CreateRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i< 10; i++) {System.out.println("i:" + i);}} }public class ThreadDemo2 {public static void main(String[] args) {System.out.println("-----多線程創(chuàng)建開始-----");/* 1.創(chuàng)建一個線程 */CreateRunnable createThread = new CreateRunnable();/* 2.開始執(zhí)行線程 注意 開啟線程不是調(diào)用run方法,而是start方法 */System.out.println("-----多線程創(chuàng)建啟動-----");Thread thread = new Thread(createThread);thread.start();System.out.println("-----多線程創(chuàng)建結(jié)束-----");} }

打印結(jié)果:

-----多線程創(chuàng)建開始----- -----多線程創(chuàng)建啟動----- -----多線程創(chuàng)建結(jié)束----- i:0 i:1 i:2 i:3 i:4 i:5 i:6 i:7 i:8 i:9
使用繼承Thread類還是使用實現(xiàn)Runnable接口好?

使用實現(xiàn)Runnable接口好,繼承方式的擴展性不強,java總只支持單繼承,如果一個類繼承Thread就不能繼承其他的類了。

4、守護線程

java 中有兩種線程,一種是用戶線程,一種是守護線程。

  • 用戶線程:指用戶自定義創(chuàng)建的線程,主線程停止,用戶線程不會停止。

  • 守護線程:當前進程不存在或主線程停止,守護進程也會被停止。

如何使用守護線程?

只需要調(diào)用 setDaemon(true) 方法即可設置為守護線程。

/*** author: niceyoo* blog: https://cnblogs.com/niceyoo* desc:*/ public class DaemonThread {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(100);} catch (Exception e) {}System.out.println("我是子線程...");}}});thread.setDaemon(true);thread.start();for (int i = 0; i < 10; i++) {try {Thread.sleep(100);} catch (Exception e) {}System.out.println("我是主線程");}System.out.println("主線程執(zhí)行完畢!");} }

運行結(jié)果:

... 我是主線程 我是子線程... 我是主線程 主線程執(zhí)行完畢!

從運行結(jié)果看到,main函數(shù)執(zhí)行完了,守護線程也跟著停止了。

5、多線程運行狀態(tài)

線程從創(chuàng)建、運行到結(jié)束,總是處于下面五個狀態(tài)之一:

新建狀態(tài)、就緒狀態(tài)、運行狀態(tài)、阻塞狀態(tài)以及死亡狀態(tài)。

5.1、新建狀態(tài)

當用new操作符創(chuàng)建一個線程時, 例如new Thread?,線程還沒有開始運行,此時線程處在新建狀態(tài)。 當一個線程處于新生狀態(tài)時,程序還沒有開始運行線程中的代碼

5.2、就緒狀態(tài)

一個新創(chuàng)建的線程并不自動開始運行,要執(zhí)行線程,必須調(diào)用線程的start()方法。當線程對象調(diào)用start()方法即啟動了線程,start()方法創(chuàng)建線程運行的系統(tǒng)資源,并調(diào)度線程運行run()方法。當start()方法返回后,線程就處于就緒狀態(tài)。

處于就緒狀態(tài)的線程并不一定立即運行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間才可以運行線程。因為在單CPU的計算機系統(tǒng)中,不可能同時運行多個線程,一個時刻僅有一個線程處于運行狀態(tài)。因此此時可能有多個線程處于就緒狀態(tài)。對多個處于就緒狀態(tài)的線程是由Java運行時系統(tǒng)的線程調(diào)度程序(thread scheduler)來調(diào)度的。

5.3、運行狀態(tài)

當線程獲得CPU時間后,它才進入運行狀態(tài),真正開始執(zhí)行run()方法.

5.4、阻塞狀態(tài)

線程運行過程中,可能由于各種原因進入阻塞狀態(tài):

  • 線程通過調(diào)用sleep方法進入睡眠狀態(tài);
  • 線程調(diào)用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調(diào)用者;
  • 線程試圖得到一個鎖,而該鎖正被其他線程持有;
  • 線程在等待某個觸發(fā)條件;
  • 5.5、死亡狀態(tài)

    有兩個原因會導致線程死亡:

  • run方法正常退出而自然死亡,
  • 一個未捕獲的異常終止了run方法而使線程猝死。
  • 為了確定線程在當前是否存活著(就是要么是可運行的,要么是被阻塞了),需要使用 isAlive() 方法。如果是可運行或被阻塞,這個方法返回true; 如果線程仍舊是new狀態(tài)且不是可運行的, 或者線程死亡了,則返回false.

    6、join()方法的作用

    在多線程中也是有執(zhí)行的優(yōu)先級的,所謂的優(yōu)先級,就是cpu是否格外關注這位小兄弟,優(yōu)先級越大,自然獲得的好處就越多。

    當在主線程當中執(zhí)行到 小弟.join() 方法時,就認為主線程應該把執(zhí)行權(quán)讓給 小弟。

    舉一個例子:

    創(chuàng)建一個線程,如何讓子線程執(zhí)行完畢后,主線程才能執(zhí)行呢?

    public class ThreadDemo3 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(10);} catch (Exception e) {}System.out.println(Thread.currentThread().getName() + "i:" + i);}}});t1.start();/* 當在主線程當中執(zhí)行到t1.join()方法時,就認為主線程應該把執(zhí)行權(quán)讓給t1 */t1.join();for (int i = 0; i < 10; i++) {try {Thread.sleep(10);} catch (Exception e) {}System.out.println("main" + "i:" + i);}} }

    打印結(jié)果:

    Thread-0i:0 Thread-0i:1 Thread-0i:2 Thread-0i:3 Thread-0i:4 Thread-0i:5 Thread-0i:6 Thread-0i:7 Thread-0i:8 Thread-0i:9 maini:0 maini:1 maini:2 maini:3 maini:4 maini:5 maini:6 maini:7 maini:8 maini:9

    7、優(yōu)先級

    雖然上邊在介紹 join 方法時提到了優(yōu)先級,但是在使用 join() 方法后,該線程卻變成了完全主導,這或許并不是你想要的結(jié)果。

    現(xiàn)代操作系統(tǒng)基本采用時分的形式調(diào)度運行的線程,線程分配得到的時間片的多少決定了線程使用處理器資源的多少,也對應了線程優(yōu)先級這個概念。在JAVA線程中,通過一個int priority來控制優(yōu)先級,范圍為1-10,其中10最高,默認值為5。下面是源碼(基于1.8)中關于priority的一些量和方法。

    class PrioritytThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().toString() + "---i:" + i);}} }public class ThreadDemo4 {public static void main(String[] args) {PrioritytThread prioritytThread = new PrioritytThread();Thread t1 = new Thread(prioritytThread);Thread t2 = new Thread(prioritytThread);t1.start();/* 注意設置了優(yōu)先級, 不代表每次都一定會被執(zhí)行。 只是CPU調(diào)度會有限分配 */t1.setPriority(10);t2.start();} }

    打印結(jié)果:

    Thread[t1,10,main]---i:0 Thread[t1,10,main]---i:1 Thread[t1,10,main]---i:2 Thread[t1,10,main]---i:3 Thread[t1,10,main]---i:4 Thread[t1,10,main]---i:5 Thread[t1,10,main]---i:6 Thread[t1,10,main]---i:7 Thread[t1,10,main]---i:8 Thread[t1,10,main]---i:9 Thread[t2,5,main]---i:0 Thread[t2,5,main]---i:1 Thread[t2,5,main]---i:2 Thread[t2,5,main]---i:3 Thread[t2,5,main]---i:4 Thread[t2,5,main]---i:5 Thread[t2,5,main]---i:6 Thread[t2,5,main]---i:7 Thread[t2,5,main]---i:8 Thread[t2,5,main]---i:9

    7、常見的面試題

    進程與線程的區(qū)別?

    答:進程是所有線程的集合,每一個線程是進程中的一條執(zhí)行路徑。

    為什么要用多線程?

    答:提高程序效率

    多線程創(chuàng)建方式?

    答:繼承Thread或Runnable 接口。

    使用繼承Thread類還是使用實現(xiàn)Runnable接口好?

    答:實現(xiàn)Runnable接口好,繼承方式的擴展性不強,java總只支持單繼承,如果一個類繼承Thread就不能繼承其他的類了。

    你在哪里用到了多線程?

    答:主要能體現(xiàn)到多線程提高程序效率。

    舉例:分批發(fā)送短信。

    8、最后總結(jié)

    我們了解了什么是線程,線程是一條執(zhí)行路徑,每個線程互不影響;

    了解了什么是多線程,多線程在一個線程中,有多條不同的執(zhí)行路徑,并行執(zhí)行,目的為了提高程序效率。

    了解了線程創(chuàng)建常見的兩種方式:繼承Thread類實現(xiàn)run方法,或者實現(xiàn)Runnable接口。

    事實上,實際開發(fā)中這兩種方式并不常見,而是使用線程池來進行管理。

    了解了線程的幾種狀態(tài),新建、就緒、運行、阻塞、死亡。

    了解了線程里面也是有優(yōu)先級的,用數(shù)值1-10來記錄,默認是5,最大是10,通過調(diào)用 setPriority(10) 來設置優(yōu)先級,需要一提的是,并不是優(yōu)先級越大就一定要先執(zhí)行完,只是優(yōu)先執(zhí)行完的概率要大。

    我創(chuàng)建了一個java相關的公眾號,用來記錄自己的學習之路,感興趣的小伙伴可以關注一下微信公眾號哈:niceyoo

    總結(jié)

    以上是生活随笔為你收集整理的并发编程快速入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。