最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程編程:線程的原理和使用安全

 更新時間:2026年05月02日 09:39:58   作者:jjjava2.0  
文章主要介紹了線程的基本概念、線程和進程的區(qū)別、線程的創(chuàng)建方法、線程的常見方法與屬性、線程的安全問題等,線程是程序執(zhí)行流的最小單位,可以并發(fā)執(zhí)行并共享數(shù)據(jù),線程的生命周期狀態(tài)包括新建、就緒、運行、阻塞、死亡等

一,認識線程

1.1 什么是線程

        一個線程就是一個“執(zhí)行流”,每個線程之間都可以按照順序執(zhí)行自己的代碼,多個線程之間“同時”執(zhí)行著多份代碼。同時,線程也是 CPU 真正執(zhí)行任務的單位。

舉個栗子:去奶茶店買奶茶(奶茶店中有自己獨立的“程序”讓我們拿到奶茶,所以也可把這個看為一個線程),奶茶店有不同崗位員工,每個員工都是獨立的“執(zhí)行流”。如果店里只有一個員工(單線程),那速度將會很慢效率極低;多個員工分工合作(多線程),那效率會得到大幅提高,這就是多線程的優(yōu)勢。

2.2 線程和進程的區(qū)別

進程包含線程的每個進程至少有一個線程存在(主線程)

線程(Thread)進程
線程時cpu上調度執(zhí)行的基本單位進程是操作系統(tǒng)中資源分配的基本單位
資源共享進程內存獨立內存,互不影響
開銷輕量,快速(只有第一個線程也就是和進程一起創(chuàng)建時,需要申請資源,后續(xù)創(chuàng)建則不需要)創(chuàng)建/銷毀慢,消耗資源
奔潰影響一個崩潰,可能把同進程內的線程都帶崩潰一個崩潰不影響其他

二,創(chuàng)建線程

2.1 繼承Thread類,重寫run方法

class Thread1 extends Thread{
    public void run(){
        System.out.println("線程運行代碼");
    }
}

//創(chuàng)建實例
    Thread1 t = new Thread(); 

2.2 實現(xiàn)Runnable接口,重寫run方法

clas Runnable1 implements Runnable{
    public void run(){
        System.out.println("線程運行代碼");
    }
}
//創(chuàng)建實例
    Thread t = new Thread(new Runnable());

2.3  匿名內部類(本質就是方法1,2)

        2.3.1 用匿名內部類創(chuàng)建Tread子類對象

Thread t1 = new Thread(){
    public void run(){
        System.out.println("使用匿名類創(chuàng)建Tread子類對象");
    }
}

        2.3.2 用匿名內部類創(chuàng)建Runnable子類對象

Thread t2 = new Thread(new Runnable(){
    public void run(){
        System.out.println("使用匿名類創(chuàng)建Runnable子類對象");
    }
});

這兩個線程對象(t1t2)的 start() 方法都只能調用一次,所以從 “啟動線程” 的角度來說,它們是一次性的;但第二種寫法里的 Runnable 任務邏輯,是可以被復用的。

2.4 用lambda表達式(常用)

 //使用lambda 表達式創(chuàng)建Runnable 子類對象
Thread t3 = new Thread (() -> System.out.println("使用匿名類創(chuàng)建Thread 子類對象"));


Thread t4 = new Thread (() -> {
     System.out.println("使用匿名類創(chuàng)建Thread 子類對象");
 });

2.5 實現(xiàn)Callable

// 用匿名內部類創(chuàng)建Callable對象
Callable<String> callableTask = new Callable<String>() {
    public String call() throws Exception {
        return "Callable任務執(zhí)行完成,返回結果";
    }
};

// 包裝成FutureTask,再交給Thread
FutureTask<String> futureTask = new FutureTask<>(callableTask);
Thread t5 = new Thread(futureTask);

2.6 線程池(ThreadFactory)

// 用匿名內部類創(chuàng)建ThreadFactory
ThreadFactory factory = new ThreadFactory() {
    private int count = 0;
    public Thread newThread(Runnable r) {
        // 自定義線程名,方便調試
        return new Thread(r, "自定義線程-" + (++count));
    }
};

// 創(chuàng)建固定大小線程池
ExecutorService pool = Executors.newFixedThreadPool(3, factory);

// 提交任務(用匿名內部類Runnable)
pool.submit(new Runnable() {
    public void run() {
        System.out.println("線程池中的任務執(zhí)行");
    }
});

// 關閉線程池
pool.shutdown();

三,Thread類

2.1 常見構造方法

方法說明
Thread()創(chuàng)建線程對象
Thread(Runnable target)使用Runnable對象創(chuàng)建線程對象
Thread(String name)創(chuàng)建線程對象,并命名
Thread(Runnable target,String name)使用Runnable對象創(chuàng)建線程對象并命名
Thread(ThreadGroup gruop,Runnable target)線程可以被用來分組管理,分好的組為線

2.2 常見屬性

屬性獲取方法

說明

IDgetID( )ID是線程的唯一標識,不同的線程不會重復
名稱getName( )名稱在各種調試工具用到
狀態(tài)getState( )表示線程當前所處的一個情況
優(yōu)先級getPriority( )優(yōu)先級高的線程理論上來說更容易被調度到
是否后臺線程isDaemon( )JVM會在一個進程的所有非后臺線程結束后,才會結束運行
是否存活isAlive( )簡單的理解,為run 方法是否運行結束了
是否被中斷isInterrupted( ) 檢查線程是否收到中斷信號

四,線程相關操作

4.1 啟動線程 start(  )

         上面我們介紹了覆寫run( )方法創(chuàng)建一個線程對象,但線程對象被創(chuàng)建出來并不意味著線程已經(jīng)開始運行了,而調用start( )方法,才真的在操作系統(tǒng)的底層創(chuàng)建出一個線程,線程才真正的獨立執(zhí)行

舉個栗子:我(主線程)奶茶店店長,我先寫了一份完整的“工作流程”(new Thread()),我在紙上寫下了做奶茶的步驟(run( ) 方法),這是我自己按照流程做一杯(調用run( ),并不會啟動新的線程)。然后我畫了個店員的名牌,寫著 “店員 A”(創(chuàng)建了線程對象),此時店員A開始按步驟工作(調用start( )),這是店里就我和店員A同時干活,效率提升。

4.2 中斷線程

舉個栗子:我(主線程)安排店員A(子線程)去做奶茶,3秒之后,我告訴店員A“先不做奶茶了,過來點單”,店員A立刻停下做奶茶,去點單。

 常見的有以下兩種方法:

a)通過共享的標記來進行溝通,使用自定義變量作為標志位(volatile

b)調用interrupt(方法來通知)

代碼實例:

//采用  a)方法

public class demo {
    private static class MyRunnable implements Runnable{
        //volatile相當于一個主線程和子線程公用的開關
        public volatile boolean isQuit=false;
        @Override
        public void run() {
            while(!isQuit){
        //如果沒有收到停止指令,循環(huán)一直滿足,開始做奶茶
                System.out.println(Thread.currentThread().getName()+":我正在忙著做奶茶");
                try{
        //做一杯奶茶需要1s,也就是1s打印一次
                    Thread.sleep(1000);//這里把光標放在sleep下用alt+enter快捷鍵可以直接生成try,catch
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        //不進入while循環(huán)也就是收到停止指令時
            System.out.println(Thread.currentThread().getName()+":我現(xiàn)在來幫忙點單");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyRunnable target=new MyRunnable();
        Thread thread=new Thread(target,"店員A");
        System.out.println(Thread.currentThread().getName()+":A,快去做奶茶");
        //讓A開始工作
        thread.start();
        //我去做3秒的事,a接著做奶茶每秒打印一次
        Thread.sleep(3000);
        //sleep結束,我叫a停止做奶茶
        System.out.println(Thread.currentThread().getName()+":A先別做奶茶了,快過來幫忙點單");
        target.isQuit=true;
    }
}

volatile就是保證:主線程改了isQuit,子線程可以立刻獲取。其核心就是修改了內存可見性問題(內存可見性將下面線程安全產(chǎn)生原因中進行詳細講解)

//采用   b)方法

public class demo2 {
    private static class MyRunnable implements Runnable{
        @Override
        public void run() {
            //while(!Thread.isterrupted())
            while (!Thread.currentThread().isInterrupted()){
                System.out.println(Thread.currentThread().getName()+":我正忙著做奶茶");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //收到中斷信號,處理異常
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().getName()+":收到通知,停下手中的活");
                    //需著重注意這里的break,跳出循環(huán),結束當前任務
                    break;
                }
            }
            //循環(huán)結束,執(zhí)行中斷后的收尾工作
            System.out.println(Thread.currentThread().getName()+":我現(xiàn)在過來點單");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyRunnable target=new MyRunnable();
        Thread thread=new Thread(target,"A");
        System.out.println(Thread.currentThread().getName()+":快去做奶茶");
        thread.start();
        Thread.sleep(5000);
        System.out.println(Thread.currentThread().getName()+":A先別做奶茶了過來點單");
        thread.interrupt();
    }
}
方法類型作用是否清除中斷標志
Thread.currentThread().isInterrupted()實例方法檢查當前線程的中斷狀態(tài)? 不清除
Thread.interrupted()靜態(tài)方法檢查當前線程的中斷狀態(tài)? 會清除(調用后標志位變?yōu)?code>false)

使用Thread.interrupted( )方法來通知線程結束Thread.currentThread( ).isInterrupted( )代替自定義標志位

在這里thread收到通知有兩種方法

1.如果線程因為調用wait/join/sleep等方法而阻塞掛起,則以InterruptedException 異常的形式通知,清除中斷標志,這個時候可以在catch中加入break;

2.只是內部的一個中斷標志被設置,thread 可以通過Thread.currentThread().isInterrupted()判斷指定線程的中斷標志被設置,不清除中斷標志這種方式通知收到的更及時,即使線程正在sleep 也可以馬上收到。

4.3 等待線程 join(  )

join可以要求多個線程間結束的線程順序

t.join( )就是等t線程結束在完成別的,只要t不結束就一直等

方法說明
public void join()等待線程結束
public void join(long millis)等待線程結束,最多等millis毫秒
public void join(long millis,int nanos)等待線程結束,精度更高
public class demo3 {
    public static void main(String[] args) throws InterruptedException {
        Runnable target=()->{
         for(int i=0;i<3;i++){
                try {
                    System.out.println(Thread.currentThread().getName()+ ":我還在工作!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":我結束了!");
        };
        Thread thread1=new Thread(target,"A");
        Thread thread2=new Thread(target,"B");
        System.out.println("先讓A開始工作");
        thread1.start();
        thread1.join();
        System.out.println("A工作結束,B開始工作");
        thread2.start();
        thread2.join();
        System.out.println("B工作結束");
    }
}

這里的拋異常也不需要手動去寫,alt+enter快捷鍵即可

4.4 獲取當前線程引用

已經(jīng)很熟悉了就不再贅述了

public static Thread currentThread( );  //返回當前線程對象的引用

4.5 休眠線程 sleep

因為線程的調度是不可控的,這個方法只能保證實際休眠時間是大于等于參數(shù)設置的休眠時間

方法說明
public static void sleep(long millis)throws InterruptedException休眠當前線程millis毫秒
public static void sleep(long millis,int nanos)throws InterruptedException更高精度的休眠

這里的拋異常也不需要手動去寫,alt+enter快捷鍵即可

五,線程狀態(tài)

查看所有線程狀態(tài)代碼:

public class demo4 {
    public static void main(String[] args) {
        for (Thread.State state:Thread.State.values()) {
            System.out.println(state);
        }
    }
}

代碼運行結果:

NEW:安排了工作,還未開始行動

RUNNABLE:可工作的.又可以分成正在工作中和即將開始工作.(就緒:線程在cpu上執(zhí)行;線程隨時可以去cpu上執(zhí)行)

BLOCKED:表示排隊等著其他事情(由于鎖導致的阻塞)

WAITING:表示排隊等著其他事情(死等,無超時時間阻塞等待)

TIMED_WAITING:表示排隊等著其他事情(線程阻塞,不參與cpu調度,不繼續(xù)執(zhí)行,阻塞時間是有上限的)

TERMINATED:工作完成了,內核中的線程已結束,但Thread對象還在

六,線程安全

6.1 什么是線程安全

一段代碼,如果多線程環(huán)境下代碼運行的結果是符合預期的(在單線程環(huán)境應該的結果),則說這個程序是線程安全的。

6.2 線程安全問題產(chǎn)生原因

1)操作系統(tǒng)對于線程的調度使搶占式隨即執(zhí)行的(根本原因)

2)多個線程同時修改同一個變量

3)修改操作不是原子的(如果修改操作只是對應一個cpu指令,就認為是原子的)

4)內存可見性問題(內存可見性:即一個線程對共享變量值的修改能夠及時的被其他線程看見)

5)指令重排序問題

七,小結

文章主要介紹了線程的基本概念、線程和進程的區(qū)別、線程的創(chuàng)建方法、線程的常見方法與屬性、線程的安全問題題,其中,線線程是CPU執(zhí)行任務的單位user補充一下,線程是程序的基本單位,線程是程序執(zhí)行流的最小單位;線程之間可以并發(fā)執(zhí)行,并共享數(shù)據(jù),一個程序至少有一個線程;線;線程的生命周期狀態(tài)包括新建、就緒、運行、阻塞、死亡等;線程間通信通過共享變量、信號量等互斥量等進行;線程的安全性則關鍵性是否變量的可見性;線程的優(yōu)先級與影響線程的調度;線程池可以復用管理線程,減少線程創(chuàng)建銷毀的開;創(chuàng)建線程池的方法包括自定義實現(xiàn)的線程池常使用的的線程池類;線程的常用方法包括is、join、sleep,interrupt等;線程的狀態(tài)包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINMIN,;線線程安全問題主要由操作系統(tǒng)調度引起的、線程間共享變量的可見引起的、非原子操作引起的、指令重排序引起的。

到此這篇關于Java多線程編程:線程的原理和使用安全的文章就介紹到這了,更多相關Java多線程編程內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java執(zhí)行SQL語句實現(xiàn)查詢的通用方法詳解

    java執(zhí)行SQL語句實現(xiàn)查詢的通用方法詳解

    這篇文章主要介紹了java執(zhí)行SQL語句實現(xiàn)查詢的通用方法詳解,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • SpringBoot如何導出Jar包并測試(使用IDEA)

    SpringBoot如何導出Jar包并測試(使用IDEA)

    這篇文章主要介紹了SpringBoot如何導出Jar包并測試(使用IDEA),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java?Base64?加密與解密示例代碼

    Java?Base64?加密與解密示例代碼

    基本的加密盡量保持簡單,加密輸入字符串沒有增加任何換行符。輸出被映射到“A-Za-z0-9+/”字符集中,解密從該字符集中解析為任意字符,這篇文章主要介紹了Java?Base64?加密與解密,需要的朋友可以參考下
    2022-12-12
  • java反射拼接方法名動態(tài)執(zhí)行方法實例

    java反射拼接方法名動態(tài)執(zhí)行方法實例

    下面小編就為大家?guī)硪黄猨ava反射拼接方法名動態(tài)執(zhí)行方法實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • Java?BigDecimal?解決浮點精度問題(用法實踐)

    Java?BigDecimal?解決浮點精度問題(用法實踐)

    本文詳細介紹了Java中BigDecimal類的原理、用法及最佳實踐,用于解決浮點數(shù)精度丟失問題,特別是在金融計算等對精度要求極高的場景中,本文將詳細講解其原理、用法及最佳實踐,感興趣的朋友跟隨小編一起看看吧
    2026-02-02
  • java字符串與日期類型轉換的工具類

    java字符串與日期類型轉換的工具類

    這篇文章主要為大家詳細介紹了java字符串與日期類型轉換的工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • 詳解Java內存管理中的JVM垃圾回收

    詳解Java內存管理中的JVM垃圾回收

    這篇文章給大家分享了關于Java內存管理中的JVM垃圾回收的相關知識點內容,有興趣的朋友們可以學習參考下。
    2018-08-08
  • java秒殺系統(tǒng)常見問題庫存超賣解決實例分析

    java秒殺系統(tǒng)常見問題庫存超賣解決實例分析

    這篇文章主要為大家介紹了java秒殺系統(tǒng)常見問題庫存超賣解決實例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Springboot項目如何兼容老的Spring項目問題

    Springboot項目如何兼容老的Spring項目問題

    這篇文章主要介紹了Springboot項目如何兼容老的Spring項目問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • springboot項目獲取請求頭當中的token的方法

    springboot項目獲取請求頭當中的token的方法

    本文主要介紹了springboot項目獲取請求頭當中的token的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-11-11

最新評論

台中市| 明光市| 灵川县| 黄冈市| 宁晋县| 万源市| 文安县| 五华县| 开阳县| 洱源县| 北票市| 调兵山市| 剑河县| 临猗县| 沾化县| 岑巩县| 师宗县| 时尚| 徐汇区| 苏尼特右旗| 江都市| 隆尧县| 滦南县| 陇川县| 东阿县| 荃湾区| 衡山县| 台东县| 岳池县| 读书| 龙川县| 杂多县| 林甸县| 河间市| 正安县| 忻城县| 柞水县| 鹿泉市| 锡林浩特市| 奉贤区| 奉化市|