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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

【Java基础】一篇文章读懂多线程

發(fā)布時間:2024/10/8 java 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Java基础】一篇文章读懂多线程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.多線程

1.1并發(fā)和并行

  • 并發(fā):兩個或多個事件在同一時間段發(fā)生
  • 并行:兩個或多個事件在同一時刻發(fā)生

1.2線程和進(jìn)程

  • 進(jìn)程是程序的一次執(zhí)行過程,進(jìn)程是系統(tǒng)運行應(yīng)用程序的基本單位,一個應(yīng)用程序可以同時運行多個進(jìn)程
  • 線程是進(jìn)程中的一個執(zhí)行單元,一個進(jìn)程至少由一個線程,負(fù)責(zé)程序的執(zhí)行

1.3線程調(diào)度的兩種方式

  • 分時調(diào)度:所有線程輪流使用CPU,平均分配每個線程使用CPU的時間
  • 搶占式調(diào)度:Java讓優(yōu)先級高的線程執(zhí)行,優(yōu)先級相同則隨機選擇一個線程執(zhí)行

1.4創(chuàng)建多線程的兩種方式

  • 多個線程在不同的棧空間里執(zhí)行,互不影響

  • 第一種實現(xiàn)方式:創(chuàng)建Thread的子類,并且重寫run方法,一般不用

public class Main {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();for (int i = 0; i < 10; i++) {System.out.println("主線程執(zhí)行:" + i);}} }class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("自定義線程執(zhí)行:" + i);}} }
  • 第二種實現(xiàn)方式:實現(xiàn)Runnable接口,重寫run方法,使用Thread(Runnable target)分配Thread對象
  • 實現(xiàn)Runnable接口創(chuàng)建多線程的好處
    • 避免單繼承的局限性
    • 將設(shè)置線程任務(wù)和開啟線程兩個過程解耦
public class Main {public static void main(String[] args) {RunnableImpl run = new RunnableImpl();Thread thread = new Thread(run);thread.start();new Thread(new RunnableImpl()).start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}} }class RunnableImpl implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}} }

1.5獲取線程名稱的兩種方式

  • String getName() 返回線程名稱
  • static Thread currentThread() 返回當(dāng)前正在執(zhí)行線程的引用
public class Main {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();for (int i = 0; i < 10; i++) {System.out.println("主線程執(zhí)行:" + i);}//獲取線程名稱方法二String name = Thread.currentThread().getName();System.out.println(name);//main} }class MyThread extends Thread {@Overridepublic void run() {//獲取線程名稱方法一String name = getName();System.out.println(name);//Thread-0for (int i = 0; i < 10; i++) {System.out.println("自定義線程執(zhí)行:" + i);}} }

2.線程安全

2.1線程同步

  • 當(dāng)使用多線程訪問同一資源時,且多個線程對資源有寫操作,容易出現(xiàn)線程安全問題,Java中使用同步機制解決

    public class Main {public static void main(String[] args) {RunnableImpl runnable = new RunnableImpl();//三個線程共享一個實現(xiàn)類對象,保證共享資源為100張票new Thread(runnable).start();new Thread(runnable).start();new Thread(runnable).start();//出現(xiàn)重復(fù)的票和不存在的票} }class RunnableImpl implements Runnable {//定義一個多線程共享的資源private int ticket = 100;//設(shè)置線程任務(wù)買票@Overridepublic void run() {//讓買票操作重復(fù)執(zhí)行while (true) {//先判斷票是否存在if (ticket > 0) {//提高安全問題出現(xiàn)的概率try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//執(zhí)行賣票操作System.out.println(Thread.currentThread().getName() + "-->" + ticket);ticket--;}}} }
  • 同步代碼塊解決線程安全問題:把可能出現(xiàn)安全問題的代碼塊用synchronized修飾

    public class Main {public static void main(String[] args) {RunnableImpl runnable = new RunnableImpl();//三個線程共享一個實現(xiàn)類對象,保證共享資源為100張票new Thread(runnable).start();new Thread(runnable).start();new Thread(runnable).start();//出現(xiàn)重復(fù)的票和不存在的票} }class RunnableImpl implements Runnable {//定義一個多線程共享的資源private int ticket = 100;//創(chuàng)建一個鎖對象Object object = new Object();//設(shè)置線程任務(wù)買票@Overridepublic void run() {//讓買票操作重復(fù)執(zhí)行while (true) {synchronized (object) {//先判斷票是否存在if (ticket > 0) {//提高安全問題出現(xiàn)的概率try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//執(zhí)行賣票操作System.out.println(Thread.currentThread().getName() + "-->" + ticket);ticket--;}}}} }
  • 同步方法解決線程安全問題:把可能出現(xiàn)安全問題的代碼塊形成一個方法并用synchronized修飾該方法

    public class Main {public static void main(String[] args) {RunnableImpl runnable = new RunnableImpl();//三個線程共享一個實現(xiàn)類對象,保證共享資源為100張票new Thread(runnable).start();new Thread(runnable).start();new Thread(runnable).start();//出現(xiàn)重復(fù)的票和不存在的票} }class RunnableImpl implements Runnable {//定義一個多線程共享的資源private int ticket = 100;//創(chuàng)建一個同步方法public synchronized void sellTicket() {//先判斷票是否存在if (ticket > 0) {//提高安全問題出現(xiàn)的概率try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//執(zhí)行賣票操作System.out.println(Thread.currentThread().getName() + "-->" + ticket);ticket--;}}//設(shè)置線程任務(wù)買票@Overridepublic void run() {//讓買票操作重復(fù)執(zhí)行while (true) {sellTicket();}} }
  • 鎖機制解決線程安全問題:Lock接口實現(xiàn)

    public class Main {public static void main(String[] args) {RunnableImpl runnable = new RunnableImpl();//三個線程共享一個實現(xiàn)類對象,保證共享資源為100張票new Thread(runnable).start();new Thread(runnable).start();new Thread(runnable).start();//出現(xiàn)重復(fù)的票和不存在的票} }class RunnableImpl implements Runnable {//定義一個多線程共享的資源private int ticket = 100;//創(chuàng)建一個鎖對象Lock lock = new ReentrantLock();//設(shè)置線程任務(wù)買票@Overridepublic void run() {//讓買票操作重復(fù)執(zhí)行while (true) {lock.lock();//加鎖//先判斷票是否存在if (ticket > 0) {//提高安全問題出現(xiàn)的概率try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}//執(zhí)行賣票操作System.out.println(Thread.currentThread().getName() + "-->" + ticket);ticket--;}lock.unlock();//解鎖}} }

3.線程狀態(tài)

3.1等待喚醒案例:線程之間的通信

  • 創(chuàng)建一個消費者線程,調(diào)用wait方法之后,放棄CPU進(jìn)入WAITING狀態(tài)(無限等待)

  • 創(chuàng)建一個生產(chǎn)者線程,調(diào)用Notify方法喚醒消費者進(jìn)程

    /*** @ClassName WaitAndNotify* @Description TODO* @Author hulin* @Date 2020/1/23 21:11* @Version 1.0.0*/ /*進(jìn)入到TimeWaiting(計時等待)有兩種方式1.使用sleep(long m)方法,在毫秒值結(jié)束之后,線程睡醒進(jìn)入到Runnable/Blocked狀態(tài)2.使用wait(long m)方法,wait方法如果在毫秒值結(jié)束之后,還沒有被notify喚醒,就會自動醒來,線程睡醒進(jìn)入到Runnable/Blocked狀態(tài)喚醒的方法:void notify() 喚醒在此對象監(jiān)視器上等待的單個線程。void notifyAll() 喚醒在此對象監(jiān)視器上等待的所有線程。*/ public class WaitAndNotify {public static void main(String[] args) {//創(chuàng)建鎖對象,保證唯一Object obj = new Object();// 創(chuàng)建一個顧客線程(消費者)new Thread(){@Overridepublic void run() {//一直等著買包子while(true){//保證等待和喚醒的線程只能有一個執(zhí)行,需要使用同步技術(shù)synchronized (obj){System.out.println("顧客1告知老板要的包子的種類和數(shù)量");//調(diào)用wait方法,放棄cpu的執(zhí)行,進(jìn)入到WAITING狀態(tài)(無限等待)try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}//喚醒之后執(zhí)行的代碼System.out.println("包子已經(jīng)做好了,顧客1開吃!");System.out.println("---------------------------------------");}}}}.start();// 創(chuàng)建一個顧客線程(消費者)new Thread(){@Overridepublic void run() {//一直等著買包子while(true){//保證等待和喚醒的線程只能有一個執(zhí)行,需要使用同步技術(shù)synchronized (obj){System.out.println("顧客2告知老板要的包子的種類和數(shù)量");//調(diào)用wait方法,放棄cpu的執(zhí)行,進(jìn)入到WAITING狀態(tài)(無限等待)try {obj.wait();} catch (InterruptedException e) {e.printStackTrace();}//喚醒之后執(zhí)行的代碼System.out.println("包子已經(jīng)做好了,顧客2開吃!");System.out.println("---------------------------------------");}}}}.start();//創(chuàng)建一個老板線程(生產(chǎn)者)new Thread(){@Overridepublic void run() {//一直做包子while (true){//花了5秒做包子try {Thread.sleep(5000);//花5秒鐘做包子} catch (InterruptedException e) {e.printStackTrace();}//保證等待和喚醒的線程只能有一個執(zhí)行,需要使用同步技術(shù)synchronized (obj){System.out.println("老板5秒鐘之后做好包子,告知顧客,可以吃包子了");//做好包子之后,調(diào)用notify方法,喚醒顧客吃包子//obj.notify();//如果有多個等待線程,隨機喚醒一個obj.notifyAll();//喚醒所有等待的線程}}}}.start();} }

3.2等待喚醒機制

  • 多個線程在處理同一個資源且任務(wù)不同時,需要線程通信來幫助解決,需要線程通信來幫助解決線程之間對同一個資源的使用和操作。通過等待喚醒機制使各個線程有效的利用資源。
  • wait方法和notify方法都屬于Object類的方法,必須在同步代碼塊或者同步函數(shù)中使用,必須由同一個鎖對象調(diào)用

4.線程池

4.1概念

  • 容納多個線程的容器(ArrayList,LinkedList,HashSet),無需反復(fù)創(chuàng)建線程
  • 好處:降低資源消耗,提高相應(yīng)速度,提高線程的可管理性

4.2線程池的實現(xiàn)

  • 使用線程池的工廠類Executors的靜態(tài)方法生產(chǎn)一個指定數(shù)量的線程池

  • 創(chuàng)建一個類實現(xiàn)Runnable接口,重寫run方法,設(shè)置線程任務(wù)

  • 調(diào)用ExecutorService的方法submit傳遞線程任務(wù)(實現(xiàn)類),開啟線程執(zhí)行run方法

  • 使用ExecutorService的方法shutdown銷毀線程池

  • import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPool {public static void main(String[] args) {//1. 使用線程池的工廠類Executors的靜態(tài)方法生產(chǎn)一個指定數(shù)量的線程池ExecutorService es = Executors.newFixedThreadPool(2);//3. 調(diào)用ExecutorService的方法submit傳遞線程任務(wù)(實現(xiàn)類),開啟線程執(zhí)行run方法es.submit(new RunnableImpl());//pool-1-thread-2//線程池會一直開啟,使用完了會把線程自動歸還給線程池es.submit(new RunnableImpl());//pool-1-thread-2es.submit(new RunnableImpl());//pool-1-thread-1//4. 使用ExecutorService的方法shutdown銷毀線程池es.shutdown();es.submit(new RunnableImpl());//出現(xiàn)異常} } public class RunnableImpl implements Runnable {//2. 創(chuàng)建一個類實現(xiàn)Runnable接口,重寫run方法,設(shè)置線程任務(wù)@Overridepublic void run() {//獲取線程名稱System.out.println(Thread.currentThread().getName());} }

    總結(jié)

    以上是生活随笔為你收集整理的【Java基础】一篇文章读懂多线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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