亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java線程創(chuàng)建與Thread類的使用方法

 更新時間:2022年06月02日 16:03:41   作者:??未見花聞????  
這篇文章主要介紹了Java線程創(chuàng)建與Thread類的使用方法,圍繞java多線程中Thread類的使用以及有關(guān)線程對象創(chuàng)建和常用方法的相關(guān)資料展開詳細(xì)內(nèi)容,具有一定的參考價值,需要的下伙伴可以參考一下

1.線程與Thread類

1.1操作系統(tǒng)中的線程與Java線程

1.1.1線程與Thread類

線程是操作系統(tǒng)中的概念. 操作系統(tǒng)內(nèi)核實現(xiàn)了線程這樣的機(jī)制, 并且對用戶層提供了一些 API 供用戶使用(例如 Linux 的 pthread 庫).
Java 標(biāo)準(zhǔn)庫中 Thread 類可以視為是對操作系統(tǒng)提供的 API 進(jìn)行了進(jìn)一步的抽象和封裝. 也就是說Thread類的一個實例就對應(yīng)著一個線程。

1.1.2Thread類的構(gòu)造方法

序號方法名解釋
1public Thread()無參數(shù)構(gòu)造方法
2public Thread(Runnable target)傳入實現(xiàn)Runnable接口的對象(任務(wù)對象)構(gòu)造線程
3public Thread(Runnable target, String name)根據(jù)目標(biāo)任務(wù)并指定線程名創(chuàng)建線程
4public Thread(ThreadGroup group, Runnable target)根據(jù)線程組和任務(wù)創(chuàng)建線程(了解)
5public Thread(ThreadGroup group, Runnable target, String name)比構(gòu)造方法4多一個指定線程名
6public Thread(String name)指定線程名創(chuàng)建線程
7public Thread(ThreadGroup group, String name)根據(jù)線程組并指定線程名創(chuàng)建線程
8public Thread(ThreadGroup group, Runnable target, String name,long stackSize)構(gòu)造函數(shù)與構(gòu)造方法5相同,只是它允許指定線程堆棧大小

 注:線程可以被用來分組管理,分好的組即為線程組,Runnable類表示任務(wù)類,也就是線程需執(zhí)行的任務(wù)。

1.1.3啟用java線程必會的方法

想要使用java線程至少得知道Thread類中這幾個方法:

方法名解釋
public void run()該方法用來封裝線程運行時執(zhí)行的內(nèi)容
public synchronized void start()線程創(chuàng)建并執(zhí)行run方法
public static native void sleep(long millis) throws InterruptedException使線程休眠millis毫秒

創(chuàng)建Thread對象,必須重寫run方法,因為你創(chuàng)建一個線程肯定要用運行一些代碼嘛。

1.2第一個Java多線程程序

首先,我們可以創(chuàng)建一個MyThread類繼承Thread類,并重寫run方法。

class MyThread extends Thread{
    //重寫run方法
    @Override
    public void run() {
        System.out.println("你好!線程!");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        //創(chuàng)建MyThread線程對象,但是線程沒有創(chuàng)建
        Thread thread = new MyThread();
        //線程創(chuàng)建并運行
        thread.start();
    }
}

使用new創(chuàng)建線程對象,線程并沒有被創(chuàng)建,僅僅只是單純地創(chuàng)建了一個線程對象,運行start方法時才會創(chuàng)建線程并執(zhí)行run方法。

運行結(jié)果:

1.3使用Runnable對象創(chuàng)建線程

除了使用子類繼承Thread類并重寫run方法,使用子類實現(xiàn)Runnable接口(該接口中也有一個run方法,表示任務(wù)的內(nèi)容),該對象可以理解為“任務(wù)”,也就是說Thread對象可以接受Runnable引用,并執(zhí)行Runnable引用的run方法。

因為Runable是一個接口,所以需要實現(xiàn)run方法,線程Thread對象創(chuàng)建好后,此時線程并沒有創(chuàng)建運行,需要調(diào)用start方法來創(chuàng)建啟動線程。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("使用Runnable描述任務(wù)!");
    }
}

public class TestDemo3 {
    public static void main(String[] args) {
        //將Runnable任務(wù)傳給Thread對象來創(chuàng)建運行線程
        Runnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);

        thread.start();
    }
}

運行結(jié)果:

根據(jù)“低內(nèi)聚,高耦合”的

編程風(fēng)格,使用Runnable的方式創(chuàng)建更優(yōu)。

1.4使用內(nèi)部類創(chuàng)建線程

當(dāng)然也可以使用匿名內(nèi)部類,來傳入匿名對象來重寫run方法。

public class TestDemo4 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("使用匿名內(nèi)部類創(chuàng)建線程匿名對象");
            }
        };
        thread.start();
    }
}

運行結(jié)果:

1.5使用Lambda表達(dá)式創(chuàng)建線程

使用Lambda表達(dá)式,本質(zhì)還是使用匿名內(nèi)部類創(chuàng)建的Thread

public class TestDemo6 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("使用Lambda表達(dá)式表示匿名內(nèi)部類來創(chuàng)建匿名任務(wù)"));
        thread.start();
    }
}

運行結(jié)果:

1.6多線程并發(fā)執(zhí)行簡單演示

在一個進(jìn)程中至少會有一個線程,如果不使用多線程編程,一個進(jìn)程中默認(rèn)會有執(zhí)行main方法的main線程(該線程是自動創(chuàng)建的),當(dāng)你創(chuàng)建一個新的線程t,該線程會與main線程并發(fā)執(zhí)行。

public class TestDemo7 {
    public static void main(String[] args) {
        //thread 線程
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("thread線程執(zhí)行中!");
                    //為了使效果更加明顯 可以使用sleep方法設(shè)定線程睡眠時間
                    try {
                        Thread.sleep(1000);//每執(zhí)行一次循環(huán)就睡眠1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread.start();

        //main 線程
        for (int i = 0; i < 10; i++) {
            System.out.println("main線程執(zhí)行中!");
            //為了使效果更加明顯 可以使用sleep方法設(shè)定線程睡眠時間
            try {
                Thread.sleep(1000);//每執(zhí)行一次循環(huán)就睡眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

運行結(jié)果:

從上面的運行結(jié)果可以看出一個問題,因為thread線程與main線程都是每打印一句語句線程休眠1秒,兩個線程喚醒的先后順序是隨機(jī)的,這也是java多線程中的一個“萬惡之源”,這個問題給我們帶來了很多麻煩,細(xì)節(jié)等后續(xù)的博客細(xì)說。

1.7多線程并發(fā)執(zhí)行的優(yōu)勢

加入我們現(xiàn)在有一個任務(wù),就是分別將ab兩個變量都自增20億次,我們來看看使用兩個線程和單獨使用一個線程分別所需的時間是多少。

public class Test {
    private static final long COUNT = 20_0000_0000L;
    //兩個線程
    public static void many() throws InterruptedException {
        //獲取開始執(zhí)行時間戳
        long start = System.currentTimeMillis();

        Thread thread1 = new Thread(() -> {
            long a = 0;
            for (long i = 0; i < COUNT; i++) {
                a++;
            }
        });
        thread1.start();
        Thread thread2 = new Thread(() -> {
            long b = 0;
            for (long i = 0; i < COUNT; i++) {
                b++;
            }
        });
        thread2.start();

        //等待兩個線程結(jié)束 再獲取結(jié)束時的時間戳
        thread1.join();
        thread2.join();
        long end = System.currentTimeMillis();

        //執(zhí)行時間,單位為毫秒
        System.out.println("多線程執(zhí)行時間:" + (end - start) + "ms");
    }
    //單線程
    public static void single() {
        //記錄開始執(zhí)行的時間戳
        long start = System.currentTimeMillis();

        long a = 0;
        for (long i = 0; i < COUNT; i++) {
            a++;
        }
        long b = 0;
        for (long i = 0; i < COUNT; i++) {
            b++;
        }
        //獲取執(zhí)行結(jié)束時的時間戳
        long end = System.currentTimeMillis();
        System.out.println("單線程執(zhí)行時間:" + (end - start) + "ms");
    }

    public static void main(String[] args) throws InterruptedException {
        //多線程
        many();
        //單線程
        single();
    }
}

我們來看看完成這個任務(wù)所需的時間:

根據(jù)結(jié)果我們發(fā)現(xiàn)兩個線程并發(fā)執(zhí)行的時間大約是500ms左右,單線程執(zhí)行的時間大約是1000ms左右,當(dāng)然如果任務(wù)量不夠大,可能多線程相比于單線程并不會有優(yōu)勢,畢竟創(chuàng)建線程本身還是有開銷的。

2.Thread類的常用屬性與方法

2.1Thread類中的重要屬性

屬性獲取該屬性的方法
線程的唯一標(biāo)識IDpublic long getId()
線程的名稱namepublic final String getName()
線程的狀態(tài)statepublic State getState()
線程的優(yōu)先級prioritypublic final int getPriority()
線程是否后臺線程public final boolean isDaemon()
線程是否存活public final native boolean isAlive()
線程是否中斷public boolean isInterrupted()

每一個線程都擁有一個id作為標(biāo)識,其中處于同一進(jìn)程的所有線程id相同,每個進(jìn)程間都有唯一的id標(biāo)識。
線程也是擁有名字的,如果我們創(chuàng)建Thread對象時,沒有指定線程對象的名稱,則會默認(rèn)命名為Thread-i,其中i為整數(shù)。

通過了解進(jìn)程,我們知道進(jìn)程擁有3種狀態(tài),分別為阻塞,執(zhí)行和就緒。而java中的線程也有類似與這種狀態(tài)的定義,后面我們細(xì)說,優(yōu)先級也一樣就不用多說了。

java線程分為后臺線程與前臺線程,其中后臺線程不會影響到進(jìn)程的退出,而前臺線程會影響進(jìn)程的退出,比如有線程t1與線程t2,當(dāng)這兩個線程為前臺線程時,main方法執(zhí)行完畢時,t1t2不會立即退出,要等到線程執(zhí)行完畢,整個進(jìn)程才會退出,反之,當(dāng)這兩個線程為后臺線程時,main方法執(zhí)行完畢時,t1t2線程被強(qiáng)制結(jié)束,整個進(jìn)程也就結(jié)束了。

關(guān)于java線程的屬性,我們可以通過java官方的jconsole調(diào)試工具查看java線程的一些屬性。 這個工具一般在jdk的bin目錄,

雙擊打開有如下界面:

選擇需要查看的線程并查看:

選擇你需要查看的進(jìn)程屬性:

2.2Thread類中常用方法總結(jié)

2.2.1常用方法

方法名解釋
public void run()該方法用來封裝線程運行時執(zhí)行的內(nèi)容
public synchronized void start()線程創(chuàng)建并執(zhí)行run方法
public static native void sleep(long millis) throws InterruptedException使線程休眠millis毫秒
public final void join() throws InterruptedException等待線程結(jié)束(在哪個線程中調(diào)用哪個對象的join方法,哪個線程就等待哪個對象)
public final synchronized void join(long millis) throws InterruptedException等待線程結(jié)束,最多等待millis毫秒
public final synchronized void join(long millis, int nanos) throws InterruptedException指定最多等待時間等待線程,精確到納秒
public void interrupt()中斷線程對象所關(guān)聯(lián)的對象,如果線程在休眠(阻塞狀態(tài))會拋出異常通知,否則設(shè)置中斷標(biāo)志位
public static boolean interrupted()判斷當(dāng)前線程的中斷標(biāo)志位是否設(shè)置,調(diào)用后會清除線程的中斷標(biāo)志位
public boolean isInterrupted()判斷當(dāng)前線程的中斷標(biāo)志位是否設(shè)置,調(diào)用后不會影響線程的標(biāo)志位
public final synchronized void setName(String name)修改線程對象名稱
public static native Thread currentThread()獲取當(dāng)前線程對象

2.2.2中斷線程

如果我們想中斷一個正在執(zhí)行的線程,該如何做呢?最簡單但不嚴(yán)謹(jǐn)?shù)姆椒ň褪俏覀冊?code>run方法中定義一個中斷標(biāo)志位(需要中斷時標(biāo)志位為true,默認(rèn)情況為false),每次執(zhí)行具體任務(wù)時需要先判斷中斷標(biāo)志位是否為true,如果是就結(jié)束線程,否則繼續(xù)執(zhí)行。

public class TestDemo8 {
    private static boolean isQuit = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while(!isQuit) {
                //每隔1秒打印一句
                System.out.println("一個不起眼的線程!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        //main線程阻塞5秒 按理會打印5句話
        Thread.sleep(5000);
        isQuit = true;
    }
}

運行結(jié)果:

但是該方法是不夠嚴(yán)謹(jǐn)?shù)?,有些場景可能達(dá)不到預(yù)期的效果,最優(yōu)的做法就是調(diào)整線程對象或者線程類中的自帶標(biāo)志位。

方式1:使用Thread對象中的標(biāo)志位首先使用 currentThread方法獲取線程對象,然后再調(diào)用該對象中的isterrupted方法獲取該對象的中斷標(biāo)志位代替我們自己所寫的isQuit標(biāo)志位,然后等該線程運行一段時間后使用interrupt方法改變標(biāo)志位,中斷線程,寫出如下代碼,看看能不能達(dá)到預(yù)期效果:

public class TestDemo9 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() ->{
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("又是一個不起眼的線程!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();

        //main休眠5秒
        Thread.sleep(5000);

        //使用interrupt方法修改線程標(biāo)志位,使其中斷
        thread.interrupt();
    }
}

我們來看一看:

失敗了,拋出一個InterruptedException異常后,線程沒有中斷,而是繼續(xù)運行,原因是interrupt方法遇到因為調(diào)用 wait/join/sleep 等方法而阻塞的線程時會使sleep等方法拋出異常,并且中斷標(biāo)志位不會修改為true,這時我們的catch語句里面值輸出了異常信息并沒有去中斷異常,所以我們需要在catch語句中加上線程結(jié)束的收尾工作代碼和退出任務(wù)循環(huán)的break語句就可以了。

public class TestDemo9 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() ->{
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("又是一個不起眼的線程!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //收尾工作
                    System.out.println("收尾工作!");
                    break;
                }
            }
        });
        thread.start();

        //main休眠5秒
        Thread.sleep(5000);

        //使用interrupt方法修改線程標(biāo)志位,使其中斷
        thread.interrupt();
    }
}

運行結(jié)果:

方式2:使用Thread類中的標(biāo)志位除了isInterrupted,還有一個靜態(tài)方法interrupted能夠訪問類中的標(biāo)志位,一般一個程序中只有一個,我們也可以使用該靜態(tài)方法來作為中斷標(biāo)志位,然后到時機(jī)后使用interrupt方法來中斷線程執(zhí)行。

public class TestDemo10 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.interrupted()) {
                System.out.println("又又是一個不起眼的線程!");
                try {
                	//設(shè)置打印頻率為1s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //收尾工作
                    System.out.println("收尾工作!");
                    break;
                }
            }
        });
        thread.start();

        //main休眠5秒
        Thread.sleep(5000);

        //使用interrupt方法修改線程標(biāo)志位,使其中斷
        thread.interrupt();
    }
}

運行結(jié)果:

綜上所述,一般以方式1的方式無腦中斷線程就可以。

2.2.3線程等待

像上面的計算自增20億次的例子就需要線程等待join方法,main線程需要等兩個線程運行完畢后才能計算計算結(jié)束時的時間戳。
針對這一點java還準(zhǔn)備了帶參數(shù)的join方法,可以指定最長的等待時間。
還有一個細(xì)節(jié)那join方法是誰等誰呢?
我們來假設(shè)幾個線程,線程A表示調(diào)用join方法的線程,線程B表示join方法來自B線程對象,那么在A線程使用B.join方法,那就是A線程等待B線程結(jié)束。

2.2.4start方法與run方法的區(qū)別

我們知道執(zhí)行一個線程的任務(wù)就是線程對象中所重寫的run方法,那么可以直接調(diào)用run方法來代替start方法嗎?

當(dāng)然不行!因為你調(diào)用run方法就是單純地調(diào)用了Thread對象中的一個普通方法而已,并沒有創(chuàng)建一個新線程來執(zhí)行run方法,而是通過main線程來執(zhí)行的run方法,而使用start方法,會創(chuàng)建一個新線程并執(zhí)行run方法。

3.Java線程的狀態(tài)

3.1java線程中的基本狀態(tài)

操作系統(tǒng)中進(jìn)程的狀態(tài)有三種分別為阻塞,就緒和執(zhí)行,而java線程中的狀態(tài)基本上相同,但做了細(xì)分,有一點區(qū)別,我們來認(rèn)識一下。

NEW: 安排了工作, 還未開始行動,就是線程對象存在,但沒有執(zhí)行start方法,java內(nèi)部的狀態(tài),與進(jìn)程中的狀態(tài)無關(guān)。
RUNNABLE: 就緒狀態(tài)。
BLOCKED: 線程正在等待鎖釋放而引起的阻塞狀態(tài)(synchronized加鎖)。
WAITING: 線程正在等待等待喚醒而引起的阻塞狀態(tài)(waitf方法使線程等待喚醒)。
TIMED_WAITING: 在一段時間內(nèi)處于阻塞狀態(tài),通常是使用sleep或者join(帶參數(shù))方法引起。
TERMINATED:Thread對象還存在,但是關(guān)聯(lián)的線程已經(jīng)工作完成了,java內(nèi)部的狀態(tài),與進(jìn)程中的狀態(tài)無關(guān)。

3.2線程狀態(tài)轉(zhuǎn)移

我先使用一個流程圖來簡要說明狀態(tài)之間的關(guān)系:

上面這個圖簡單地說明了這幾種狀態(tài)之間的轉(zhuǎn)移,關(guān)于圖中的wait以及synchronized關(guān)鍵字會在討論線程安全問題時介紹。

這期的內(nèi)容分享了有關(guān)線程創(chuàng)建執(zhí)行以及有關(guān)Thread類中的基本方法,下期繼續(xù)介紹多線程更深入的知識,比如線程安全問題,如何加鎖等更深一點的內(nèi)容。

到此這篇關(guān)于Java線程創(chuàng)建與Thread類的使用方法的文章就介紹到這了,更多相關(guān)Java線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java 爬蟲服務(wù)器被屏蔽的解決方案

    Java 爬蟲服務(wù)器被屏蔽的解決方案

    這篇文章主要介紹了Java 爬蟲服務(wù)器被屏蔽的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • 解決異常FileNotFoundException:class path resource找不到資源文件的問題

    解決異常FileNotFoundException:class path resource找不到資源文件的問題

    今天小編就為大家分享一篇關(guān)于解決異常FileNotFoundException:class path resource找不到資源文件的問題,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Map集合之HashMap的使用及說明

    Map集合之HashMap的使用及說明

    這篇文章主要介紹了Map集合之HashMap的使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • 詳解快速搭建Spring Boot+Spring MVC

    詳解快速搭建Spring Boot+Spring MVC

    本篇文章主要介紹了詳解快速搭建Spring Boot+Spring MVC,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 手把手教你如何用JAVA連接MYSQL(mysql-connector-j-8.0.32.jar)

    手把手教你如何用JAVA連接MYSQL(mysql-connector-j-8.0.32.jar)

    這篇文章主要介紹了關(guān)于如何用JAVA連接MYSQL(mysql-connector-j-8.0.32.jar)的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MySQL具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-01-01
  • idea中如何過濾某些文件不提交的方法實現(xiàn)

    idea中如何過濾某些文件不提交的方法實現(xiàn)

    本文主要介紹了idea中如何過濾某些文件不提交,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Spring?代碼技巧梳理總結(jié)讓你愛不釋手

    Spring?代碼技巧梳理總結(jié)讓你愛不釋手

    這篇文章主要分享了Spring?代碼技巧梳理總結(jié),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-06-06
  • Java 動態(tài)數(shù)組的實現(xiàn)示例

    Java 動態(tài)數(shù)組的實現(xiàn)示例

    Java動態(tài)數(shù)組是一種可以任意伸縮數(shù)組長度的對象,本文主要介紹了Java 動態(tài)數(shù)組的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Springboot通過lucene實現(xiàn)全文檢索詳解流程

    Springboot通過lucene實現(xiàn)全文檢索詳解流程

    Lucene是一個基于Java的全文信息檢索工具包,它不是一個完整的搜索應(yīng)用程序,而是為你的應(yīng)用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta 家族中的一個開源項目,也是目前最為流行的基于 Java 開源全文檢索工具包
    2022-06-06
  • JVM原理之類加載的全過程

    JVM原理之類加載的全過程

    文章詳細(xì)介紹了Java類加載過程,包括加載、鏈接、初始化、使用和卸載五個階段,并解釋了符號引用和直接引用的區(qū)別,以及類變量和實例變量的區(qū)別,此外,還介紹了Class.forName()方法的作用和使用場景
    2025-01-01

最新評論