Java線程的基礎(chǔ)用法教程

這篇文章主要講解了“Java線程的基礎(chǔ)用法教程”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Java線程的基礎(chǔ)用法教程”吧!

為昂昂溪等地區(qū)用戶(hù)提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及昂昂溪網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站、昂昂溪網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶(hù)提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶(hù)的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

線程

線程和進(jìn)程

進(jìn)程是操作系統(tǒng)分配資源的最小單位,而線程是程序執(zhí)行的最小單位,他們都是可以并發(fā)執(zhí)行的。一個(gè)進(jìn)程至少有一個(gè)線程,這些線程共享進(jìn)程的資源空間。

線程簡(jiǎn)介

每個(gè)線程都有一個(gè)優(yōu)先級(jí),高優(yōu)先級(jí)的線程比低優(yōu)先級(jí)的線程先執(zhí)行。優(yōu)先級(jí)的取值范圍是1到10的整數(shù),默認(rèn)是5。每個(gè)線程有可能被標(biāo)記為一個(gè)守護(hù)線程。當(dāng)一個(gè)線程創(chuàng)建另外一個(gè)新的線程對(duì)象,新的線程的優(yōu)先級(jí)等于創(chuàng)建他的線程的優(yōu)先級(jí);如果新的線程對(duì)象是一個(gè)守護(hù)線程當(dāng)且僅當(dāng)創(chuàng)建他的線程是一個(gè)守護(hù)線程。

線程分類(lèi)

Java線程分為守護(hù)線程(Daemon Thread)用戶(hù)線程(User Thread)。守護(hù)線程和用戶(hù)線程基本上是一樣的,唯一的區(qū)別是如果用戶(hù)線程全部退出運(yùn)行了,不管有沒(méi)有守護(hù)線程虛擬機(jī)都會(huì)退出。守護(hù)線程的作用是為其他的線程的運(yùn)行提供服務(wù),最典型的守護(hù)線程就是GC(垃圾回收期)。

創(chuàng)建線程

創(chuàng)建線程的方式

創(chuàng)建一個(gè)線程類(lèi)有三種方式:

  • 繼承Thread類(lèi)

  • 實(shí)現(xiàn)Runnable接口

  • 實(shí)現(xiàn)Callable接口

Thread

Thread簡(jiǎn)介

Thread是創(chuàng)建線程最關(guān)鍵的一個(gè)類(lèi),這個(gè)詞本身也代表線程,Thread類(lèi)實(shí)現(xiàn)了Runnable接口。

代碼示例

public class ThreadDemo extends Thread {
	public void run() {
		for (int i = 0; i < 60; i++) {
			System.out.println(getName() + ":" + i);
		}
	}
}
public class Demo{
    public static void main(String[] args) {
        ThreadDemo t1 = new ThreadDemo();
		ThreadDemo t2 = new ThreadDemo();
		t1.start();
		t2.start();
    }
}

Runnable

Runnable簡(jiǎn)介

Runnable是提供線程的接口,有一個(gè)抽象方法public abstract void run()。實(shí)現(xiàn)了這個(gè)接口的類(lèi)必須實(shí)現(xiàn)它的run方法。

代碼示例

public class Runnable implements Runnable{
    public void run() {
       public void run() {
           for (int i = 0; i < 60; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
           }
	   }
	}
}
public class Demo{
    public static void main(String[] args) {
        RunnableDemo run = new RunnableDemo();
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        t1.start();
        t2.start();
    }
}

Callable和Future

Callable和Future簡(jiǎn)介

Thread和Runnable創(chuàng)建線程不能獲取線程的返回值。從Java1.5開(kāi)始,就提供了Callable和Future,通過(guò)他們可以在任務(wù)執(zhí)行完畢之后得到任務(wù)執(zhí)行結(jié)果。

  • Callable接口:可以返回一個(gè)結(jié)果或者拋出一個(gè)異常的一個(gè)任務(wù),實(shí)現(xiàn)者定義一個(gè)沒(méi)有參數(shù)的call方法。區(qū)別于Thread和Runnable的run方法,Calllable任務(wù)執(zhí)行的方法是call。

  • Future接口:Future接口代表了異步計(jì)算的結(jié)果,提供了一些方法用于檢查計(jì)算結(jié)果是否完成,獲取計(jì)算結(jié)果等。FutureTask類(lèi)提供了Future接口的實(shí)現(xiàn),并且實(shí)現(xiàn)了Runnable接口。

代碼案例

public class MyCallable implements Callable<Integer> {
    public Integer call() {
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        return new Integer(sum);
    }
}
public class Demo{
    public static void main(String[] args) {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> result = new FutureTask<Integer>(callable);
        new Thread(result).start();
        try {
            Integer value = result.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

線程生命周期

線程狀態(tài)

在Thread類(lèi)中有一個(gè)內(nèi)部枚舉類(lèi)State代表了線程的狀態(tài),一個(gè)線程從創(chuàng)建到銷(xiāo)毀就是一個(gè)完整的生命周期。

public enum State {
    /**
     * 線程被創(chuàng)建,還沒(méi)有開(kāi)始運(yùn)行
     */
    NEW,
    /**
     * 線程運(yùn)行狀態(tài),運(yùn)行狀態(tài)的線程是正在被Java虛擬機(jī)執(zhí)行,但是也可能正在等待操作系統(tǒng)的其他資源例如處理器
     */
    RUNNABLE,
    /**
     * 線程阻塞狀態(tài),等待監(jiān)視器鎖。處于阻塞狀態(tài)線程是在等待監(jiān)視器鎖為了:進(jìn)入同步代碼塊/方法或者被調(diào)用后重	  		 * 新進(jìn)入同步代碼/方法
     */
    BLOCKED,
    /**
     * 線程等待狀態(tài),一個(gè)線程處于等待狀態(tài)由于調(diào)用了以下這幾種方法:Object.wait;Thread.join;LockSupp
     * ort.park。處于等待的線程正在等待另一個(gè)線程執(zhí)行一個(gè)特定的操作。
     */
    WAITING,
    /**
     * 線程超時(shí)等待狀態(tài),一個(gè)線程處于超時(shí)等待狀態(tài)在一個(gè)特定的等待時(shí)間,由于調(diào)用了以下幾個(gè)方法Thread.slee
     * p;Object.wait(long);Thread.join(long);LockSupport.parkNanos;LockSupport.parkUntil。
     */
    TIMED_WAITING,
    /**
     * 線程結(jié)束狀態(tài),線程已經(jīng)執(zhí)行完成了。
     */
    TERMINATED;
}

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

線程狀態(tài)轉(zhuǎn)換圖

線程從創(chuàng)建后就在幾個(gè)狀態(tài)中切換。下面是一個(gè)線程狀態(tài)轉(zhuǎn)換圖,調(diào)用不同的方法就可以切換線程線程的狀態(tài)。

Java線程的基礎(chǔ)用法教程

運(yùn)行狀態(tài)&無(wú)限等待

調(diào)用Object.wait();Thread.join();LockSupport.park()方法可以讓線程從運(yùn)行狀態(tài)進(jìn)入到無(wú)限等待狀態(tài)。

  • wait方法

    是屬于Object類(lèi)的,對(duì)象調(diào)用wait方法后會(huì)讓當(dāng)前持有對(duì)象鎖的線程釋放當(dāng)前對(duì)象鎖并進(jìn)入等待隊(duì)列。對(duì)象調(diào)用notify從等待隊(duì)列隨機(jī)選擇一個(gè)線程喚醒去競(jìng)爭(zhēng)對(duì)象鎖,對(duì)象調(diào)用notifyall會(huì)喚醒等待隊(duì)列中的所有線程去競(jìng)爭(zhēng)對(duì)象鎖。

    public class Demo {
        public static void main(String[] args) {
            Demo demo = new Demo();
            Thread t1 = new Thread(() -> {
                synchronized (demo) {
                    System.out.println("t1 start");
                    try {
                        demo.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1 end");
                }
            });
            Thread t2 = new Thread(() -> {
               synchronized (demo) {
                   System.out.println("t2 start");
                   System.out.println("t2 end");
                   demo.notify();
               }
            });
            t1.start();
            t2.start();
        }
    }

  • join方法

    是屬于Thread類(lèi)的,join方法是阻塞調(diào)用此方法的線程,當(dāng)線程a調(diào)用線程b的b.join(long),線程a會(huì)阻塞直到線程b執(zhí)行完成。

    public class Demo {
        public static void main(String[] args) throws Exception {
          	System.out.println("main start");
            Thread t1 = new Thread(() -> {
                System.out.println("t1 start");
                System.out.println("t1 end");
            });
            t1.start();
            t1.join();
            System.out.println("main end");
        }
    }

  • park方法

    是屬于LockSupport類(lèi)的,LockSupport是一個(gè)線程阻塞工具類(lèi),所有的方法都是靜態(tài)方法,可以使用park方法來(lái)阻塞線程,使用unpart來(lái)喚醒線程。

    public class Demo {
        public static void main(String[] args) {
            System.out.println("main start");
            Thread t1 = new Thread(() -> {
                System.out.println("t1 start");
                LockSupport.park();
                System.out.println("t1 end");
            });
            t1.start();
            LockSupport.unpark(t1);
            System.out.println("main end");
        }
    }

運(yùn)行狀態(tài)&超時(shí)等待

調(diào)用Object.wait(long);Thread.join(long);LockSupport.park(long)方法可以讓線程從運(yùn)行狀態(tài)進(jìn)入到等待狀態(tài),直到到達(dá)等待時(shí)間或者主動(dòng)喚醒。

  • wait(long)方法

    是屬于Object類(lèi)的,當(dāng)對(duì)象調(diào)用wait(long)后會(huì)讓當(dāng)前持有對(duì)象鎖的線程釋放掉當(dāng)前對(duì)象鎖進(jìn)入等待隊(duì)列,直到到達(dá)等待時(shí)間或者對(duì)象調(diào)用notify或者notifyall從等待隊(duì)列中喚醒線程,線程又重新開(kāi)始競(jìng)爭(zhēng)鎖。

public class Demo {
    public static void main(String[] args) {
        Demo demo = new Demo();
        Thread t1 = new Thread(() -> {
            synchronized (demo) {
                for (int i = 0; i < 1000; i++) {
                    if (i == 500) {
                        try {
                            demo.wait(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("------t1------: " + i);
                }
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (demo) {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("------t2------: " + i);
                }
            }
        });
        t1.start();
        t2.start();
    }
}
  • join(long)方法

    是屬于Thread類(lèi)的,join(long)方法是阻塞調(diào)用此方法的線程,當(dāng)線程a調(diào)用線程b的b.join(long),線程a會(huì)阻塞直到到達(dá)阻塞時(shí)間或者線程b執(zhí)行完成。

public class Demo {
    public static void main(String[] args) throws Exception {
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("----t1----: " + i);
            }
        });
        t1.start();
        t1.join(1);
        System.out.println("main end");
    }
}
  • parkUntil(long)和parkNanos(long)

    是屬于LockSupport類(lèi)的,LockSupport是一個(gè)線程阻塞工具類(lèi),所有的方法都是靜態(tài)方法,可以使用parkUntil(long)和parkNanos(long)方法來(lái)阻塞線程。parkNanons是阻塞long時(shí)間,parkUntil是阻塞截止到long時(shí)間。

public class Demo {
    public static void main(String[] args) {
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            System.out.println("t1 start");
            LockSupport.parkNanos(3000000000L);
            System.out.println("t1 end");
        });
        t1.start();
        System.out.println("main end");
    }
}
public class Demo {
    public static void main(String[] args) throws Exception{
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            System.out.println("t1 start");
            String dateTimeStr = "2021-04-04 14:57:00";
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, df);
            LockSupport.parkUntil(dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
            System.out.println("t1 end");
        });
        t1.start();
        System.out.println("main end");
    }
}

無(wú)限等待&阻塞狀態(tài)

對(duì)象調(diào)用wait方法后線程會(huì)進(jìn)入無(wú)限等待狀態(tài),當(dāng)對(duì)象調(diào)用notify或者notifyAll時(shí),線程將從無(wú)限等待狀態(tài)進(jìn)入阻塞狀態(tài)。

阻塞狀態(tài)到運(yùn)行狀態(tài)

線程處于阻塞狀態(tài),如果獲取到鎖對(duì)象,就進(jìn)入運(yùn)行狀態(tài)。

感謝各位的閱讀,以上就是“Java線程的基礎(chǔ)用法教程”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Java線程的基礎(chǔ)用法教程這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

新聞標(biāo)題:Java線程的基礎(chǔ)用法教程
URL分享:http://bm7419.com/article18/pcgedp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站設(shè)計(jì)、品牌網(wǎng)站建設(shè)全網(wǎng)營(yíng)銷(xiāo)推廣、網(wǎng)站收錄、

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)