java多線程開(kāi)發(fā)知識(shí)點(diǎn)匯總

1.引言

最近的工作大量運(yùn)用了多線程的一些知識(shí),才發(fā)現(xiàn)自己對(duì)這塊知識(shí)有很多盲點(diǎn),于是看看書(shū),博客,寫(xiě)寫(xiě),總結(jié)總結(jié)。

2.正題

1.線程的狀態(tài)
  • 新建
    剛創(chuàng)建的時(shí)候的狀態(tài)
  • 就緒
    等待獲取cpu時(shí)間片
  • 阻塞
    阻塞狀態(tài)的線程等待一個(gè)監(jiān)視器鎖以進(jìn)入一個(gè)同步代碼塊/同步方法,或者該線程在調(diào)用wait()方法后重如該同步代碼塊/同步方法
  • 運(yùn)行
  • 死亡
1.java Thread.yield 方法

yield方法 讓出當(dāng)前Thread的cpu,使當(dāng)前線程變成就緒態(tài),和其他線程一起競(jìng)爭(zhēng)cpu資源。yield方法并沒(méi)有終止當(dāng)前線程的意思。

2.線程池shutdown 和shutdownNow
/**
     * Initiates an orderly shutdown in which previously submitted
     * tasks are executed, but no new tasks will be accepted.
     * Invocation has no additional effect if already shut down.
     *
     * <p>This method does not wait for previously submitted tasks to
     * complete execution.  Use {@link #awaitTermination awaitTermination}
     * to do that.
     *
     * @throws SecurityException {@inheritDoc}
     */

shutdown方法本質(zhì)調(diào)用線程池各個(gè)線程的interrupt()方法,調(diào)用這個(gè)方法之后,線程池將不再接受新的任務(wù),調(diào)用這個(gè)方法之后,再submit一個(gè)任務(wù)就會(huì)報(bào)RejectedExecutionException異常

/**
     * Attempts to stop all actively executing tasks, halts the
     * processing of waiting tasks, and returns a list of the tasks
     * that were awaiting execution. These tasks are drained (removed)
     * from the task queue upon return from this method.
     *
     * <p>This method does not wait for actively executing tasks to
     * terminate.  Use {@link #awaitTermination awaitTermination} to
     * do that.
     *
     * <p>There are no guarantees beyond best-effort attempts to stop
     * processing actively executing tasks.  This implementation
     * cancels tasks via {@link Thread#interrupt}, so any task that
     * fails to respond to interrupts may never terminate.
     *
     * @throws SecurityException {@inheritDoc}
     */

shutdownNow和shutdown方法一樣,唯一不同,shutdownNow會(huì)盡最大的可能去終止正在運(yùn)行的任務(wù),并且返回沒(méi)有執(zhí)行的Runnable

3.Callable vs Runnable 接口

Runnable 執(zhí)行完畢沒(méi)有返回值

Callable執(zhí)行完畢有返回值,通過(guò)Feture.get()獲取返回值,此方法會(huì)使線程進(jìn)入阻塞態(tài)

public static void main(String[] args) {
        ThreadPoolExecutor m = (ThreadPoolExecutor) Executors.newCachedThreadPool();

        Future <String>f=m.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(8000);
                return "wxy";
            }
        });

        System.out.println("開(kāi)始阻塞");
        try {
            String s=f.get();
            System.out.println(s);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("結(jié)束");
    }
4.線程優(yōu)先級(jí)

線程的等級(jí)在1-10之間,小于1 或者大于10 將報(bào)異常。優(yōu)先級(jí)越高,獲取cpu時(shí)間片越多,獲取的幾率也越大。通過(guò)setPriority方法設(shè)置

5.后臺(tái)線程

后臺(tái)線程,它是在后臺(tái)運(yùn)行的,它的任務(wù)是為其他線程提供服務(wù),這種線程被稱為“后臺(tái)線程(Daemon Thread)”,又稱為“守護(hù)線程”或“精靈線程”。JVM的垃圾回收線程就是典型的后臺(tái)線程。當(dāng)所有的用戶線程(非守護(hù)線程)
當(dāng)所有的前臺(tái)線程死亡了,后臺(tái)線程也會(huì)自動(dòng)消亡,注意的是前臺(tái)線程死亡,不等于睡眠

6.thread.join()

在線程a中調(diào)用線程b的join()方法,會(huì)中斷線程a的執(zhí)行,等待線程b執(zhí)行完畢才會(huì)在繼續(xù)執(zhí)行線程a。

public static void main(String[] args) {
        Thread thread2=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 10; i <20 ; i++) {
                    System.out.println(i);
                }
            }
        });

        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <10 ; i++) {
                    System.out.println(i);
                    if (i==5){
                        try {
                            thread2.start();
                            thread2.join();//放在start后面
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        thread1.start();
    }

輸出:
1 2 3 4 5 10 11 12  13  14  15  16  17  18 19  6  7  8  9
7.java Lock對(duì)象

synchronized 修飾的代碼塊或者方法,處于阻塞狀態(tài)的時(shí)候,那么其他線程都無(wú)法訪問(wèn)這個(gè)方法,會(huì)一直阻塞下去。為了解決這種現(xiàn)象于是出現(xiàn)了Lock。Lock是一個(gè)接口,實(shí)現(xiàn)類(lèi)是ReentrantLock ,ReentrantLock是一個(gè)可重入且獨(dú)占式的鎖,它具有與使用synchronized監(jiān)視器鎖相同的基本行為和語(yǔ)義,但與synchronized關(guān)鍵字相比,它更靈活、更強(qiáng)大,增加了輪詢、超時(shí)、中斷等高級(jí)功能。ReentrantLock,顧名思義,它是支持可重入鎖的鎖,是一種遞歸無(wú)阻塞的同步機(jī)制。除此之外,該鎖還支持獲取鎖時(shí)的公平和非公平選擇

8.volatile 關(guān)鍵字

volatile 關(guān)鍵字只能保證變量的可見(jiàn)性,在線程a中,被volatile修飾的變量a值改變,a將會(huì)通知其他所有線程從主存再次獲取a的值,這樣a改變了,那么其他線程在使用a的值的時(shí)候,是最新的值,而不是緩存下來(lái)的值

9.ThreadLocal

ThreadLocal 本地?cái)?shù)據(jù)接口,以當(dāng)前Thread 為key,value是我們set的值。相當(dāng)于為每個(gè)thread保存一個(gè)副本。這樣下次這個(gè)線程訪問(wèn)的就是自己保存的副本,保證了數(shù)據(jù)的唯一性,從根源上解決多線程問(wèn)題

10.Thread.interrupted vs thread.interrupt

image.png

這倆個(gè)方法都是用來(lái)獲取前程是否中斷的,唯一的不同點(diǎn)就是thread.interrupt不會(huì)重置狀態(tài)。Thread.interrupted會(huì)重置狀態(tài)(重置成false)。所有線程默認(rèn)是非中斷 的。重置的意思是:當(dāng)一個(gè)線程設(shè)置成中斷,第一次調(diào)用Thread.interrupted 將返回true,第二次調(diào)用將返回false。

線程池關(guān)閉某一個(gè)線程java實(shí)現(xiàn):

public static void main(String[] args) {
        ThreadPoolExecutor mThreadPoolExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
        long t=System.currentTimeMillis();
        Future mFuture = mThreadPoolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                while (Thread.interrupted() == false) {
                    System.out.println("while正在執(zhí)行");
                }
                System.out.println("當(dāng)前線程是否中斷:"+Thread.interrupted());//最后打印的為false,清除了之前的狀態(tài)
            }
        });

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        mFuture.cancel(true);
        System.out.println(System.currentTimeMillis()-t);
    }
11 線程wait 和notify/notifyall

對(duì)象.wait(): 導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的notify( ) 方法或 notifyAll( ) 方法

對(duì)象.notify():喚醒在此對(duì)象鎖上等待的單個(gè)線程

public static void main(String[] args) {
        Object m=new Object();
        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <20; i++) {
                    if (i==10){
                        synchronized (m){
                            try {
                                m.wait();//假如不要m,直接調(diào)用就會(huì)報(bào)異常
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }else {
                        System.out.println(i);
                    }
                }
            }
        });
        thread1.start();
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("喚醒線程");
        synchronized (m){
            m.notify();
        }
    }

注意點(diǎn):
含有wait 和notify 代碼塊都需要用synchronized 修飾。并且還要一樣。

12 Thread.sleep 和 Object.wait 區(qū)別

在一個(gè)加鎖了的代碼塊中執(zhí)行Thread.sleep,不會(huì)釋放鎖。

在一個(gè)加了鎖的代碼塊中執(zhí)行wait,會(huì)釋放鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容