欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解JUC并發(fā)編程中的進程與線程學(xué)習(xí)

 更新時間:2022年03月24日 16:41:12   作者:夸父號  
這篇文章主要為大家詳細介紹了JUC并發(fā)編程中的進程與線程學(xué)習(xí),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

進程與線程

進程

  • 程序由指令和數(shù)據(jù)組成,但這些指令要運行,數(shù)據(jù)要讀寫,就必須將指令加載至 CPU,數(shù)據(jù)加載至內(nèi)存。在指令運行過程中還需要用到磁盤、網(wǎng)絡(luò)等設(shè)備。進程就是用來加載指令、管理內(nèi)存、管理 IO 的
  • 當一個程序被運行,從磁盤加載這個程序的代碼至內(nèi)存,這時就開啟了一個進程。
  • 進程就可以視為程序的一個實例。大部分程序可以同時運行多個實例進程(例如記事本、畫圖、瀏覽器等),也有的程序只能啟動一個實例進程(例如網(wǎng)易云音樂、360 安全衛(wèi)士等)

線程

線程是主要負責運行指令,進程是主要管加載指令。

一個進程之內(nèi)可以分為一到多個線程。

一個線程就是一個指令流,將指令流中的一條條指令以一定的順序交給 CPU 執(zhí)行

Java 中,線程作為最小調(diào)度單位,進程作為資源分配的最小單位。 在 windows 中進程是不活動的,只是作為線程的容器

同步異步

  • 需要等待結(jié)果返回,才能繼續(xù)運行就是同步
  • 不需要等待結(jié)果返回,就能繼續(xù)運行就是異步

串行并行執(zhí)行時間

使用多核cpu并行執(zhí)行可以明顯的提高執(zhí)行效率

  • 串行執(zhí)行時間 = 各個線程時間累加和 + 匯總時間
  • 并行執(zhí)行時間 = 最慢的線程時間 + 匯總時間

注意:單核依然是并發(fā)的思想(即:cpu輪流去執(zhí)行線程,微觀上仍舊是串行),使用單核的多線程可能會比使用單核的單線程慢,這是因為多線程上下文切換反而浪費了時間。

創(chuàng)建和運行線程

1.使用 Thread

public static void main(String[] args) {
        // 創(chuàng)建線程對象
        Thread t = new Thread("線程1") {
            public void run() {
                // 要執(zhí)行的任務(wù)
                log.debug("線程1被啟動了");
            }
        };
        // 啟動線程
        t.start();
        log.debug("測試");
    }

2.使用 Runnable 配合 Thread

public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            public void run() {
                // 要執(zhí)行的任務(wù)
                log.debug("線程1被啟動了");
            }
        };
        // 創(chuàng)建線程對象
        Thread t = new Thread(runnable);
        t.setName("線程1");
        // 啟動線程
        t.start();
        log.debug("測試");
    }

這里的Runnable是一個接口,接口中只有一個抽象方法,由我們來提供實現(xiàn),實現(xiàn)中包含線程的代碼就可以了。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

Thread 與 Runnable 的關(guān)系原理分析

方法1原理分析

方法2是使用runnable對象,當成參數(shù)傳給Thread構(gòu)造方法,其中又調(diào)用了init方法,下面是Thread構(gòu)造方法的源碼

public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

繼續(xù)跟蹤查看runnable對象傳到哪里去了,可以看到又傳給了另一個重載的init,如下

private void init(ThreadGroup g, Runnable target, String name,                      long stackSize) {        init(g, target, name, stackSize, null, true);    }private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }

再次跟蹤可以看到是把runnable對象傳給了一個thread的一個成員變量

//省略部分代碼
this.target = target;

那么這個成員變量在哪里在使用了呢,經(jīng)過查找可以發(fā)現(xiàn)是在run方法里面,只不過Thread發(fā)現(xiàn)有runnable對象就會先采用runnable的run方法。

@Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

方法2原理分析

通過創(chuàng)建一個子類去重寫Thread類的run方法,這樣就不會執(zhí)行父類的run方法。

1.用 Runnable 更容易與線程池等高級 API 配合

2.用 Runnable 讓任務(wù)類脫離了 Thread 繼承體系,更靈活

方法3 FutureTask配合Thread創(chuàng)建線程

在這里插入圖片描述

Future接口中含有g(shù)et方法來返回結(jié)果的

//省略部分代碼
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

而runnable本身是沒有返回結(jié)果的,runnable不能將結(jié)果傳給其他線程。

public interface Runnable {
    public abstract void run();
}

要注意到FutureTask也實現(xiàn)了Runnable接口,也可以傳給Thread的有參構(gòu)造里面。

創(chuàng)建線程的代碼

public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 創(chuàng)建任務(wù)對象
        FutureTask<Integer> task3 = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.debug("線程1被執(zhí)行了");
                return 666;
            }
        });
        // 參數(shù)1 是任務(wù)對象; 參數(shù)2 是線程名字,推薦
        new Thread(task3, "線程1").start();
        // 主線程阻塞,同步等待 task 執(zhí)行完畢的結(jié)果
        Integer result = task3.get();
        log.debug("結(jié)果是:{}", result);
    }

查看進程

  • 任務(wù)管理器可以查看進程和線程數(shù),也可以用來殺死進程,也可以在控制臺使用tasklist查看進程taskkill殺死進程
  • jconsole 遠程監(jiān)控配置來查看

線程運行原理

JVM 中由堆、棧、方法區(qū)所組成,其中棧就是給線程使用的。

在這里插入圖片描述

方法調(diào)用時,就會對該方法產(chǎn)生一個棧幀,方法的局部變量都會在棧幀中存儲。棧是后進先出,當method2執(zhí)行完就會回收,在執(zhí)行完同時會記錄返回地址,然后在method1中繼續(xù)執(zhí)行。

線程之間的棧幀是相互獨立的,之間互不干擾。

線程上下文切換

當上下文切換時,要保存當前的狀態(tài),因為可能是時間片用完了,此時線程還沒有結(jié)束。Java中對應(yīng)的就是程序計數(shù)器

start與run方法

啟動一個線程必須要用start方法,如果直接調(diào)用類里面的run方法實際走的是main主線程。

線程start前getState()得到的是NEW

線程start后getState()得到的是RUNNABLE

public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("t1被啟動");
            }
        };
        System.out.println(t1.getState());
        t1.start();
        System.out.println(t1.getState());
    }

sleep方法

在sleep期間調(diào)用getState()方法可以得到TIMED_WAITING

public static void main(String[] args) {
        Thread t1 = new Thread("線程1") {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        log.debug("線程1 state: {}", t1.getState());
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("線程1 state: {}", t1.getState());
    }

sleep打斷

sleep可以使用interrupt方法打斷,打斷后會觸發(fā)InterruptedException異常

public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("進入睡眠");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    log.debug("被喚醒");
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        Thread.sleep(1000);
        log.debug("打斷");
        t1.interrupt();
    }

sleep防止cpu使用100%

在沒有利用cpu來計算時,不要讓while(true)空轉(zhuǎn)浪費cpu,這時可以使用yield或 sleep 來讓出cpu的使用權(quán)給其他程序

yield方法會把cpu的使用權(quán)讓出去,然后調(diào)度執(zhí)行其它線程。線程的調(diào)度最終還是依賴的操作系統(tǒng)的調(diào)度器。

join方法

該方法會等待線程的結(jié)束

static int r = 11;
    public static void main(String[] args) throws InterruptedException {
        test1();
    }
    private static void test1() throws InterruptedException {
        log.debug("主線程開始");
        Thread t1 = new Thread(() -> {
            sleep(1);
            r = 888;
        },"線程1");
        t1.start();
//        t1.join();
        log.debug(String.valueOf(r));
        log.debug("主線程線程結(jié)束");
    }

join沒有使用時,返回的是11,若是使用join返回的是888,是主線程在同步等待線程1。

當然還有其他的方法等待

1.sleep方法等待線程1結(jié)束

2.利用FutureTask的get方法

join(long n)方法可以傳入?yún)?shù),等待線程運行結(jié)束,最多等待 n 毫秒,假如執(zhí)行時間大于等待的時間,就會不再等待。那么該線程會直接結(jié)束嗎?答案是不會。

如下代碼

public class Test10 {
    static int r = 11;
    public static void main(String[] args) throws InterruptedException {
        test1();
    }
    private static void test1() throws InterruptedException {
        log.debug("主線程開始");
        Thread t1 = new Thread(() -> {
            sleep(2);
            r = 888;
            log.debug("線程1結(jié)束");
        },"線程1");
        t1.start();
        t1.join(1000);
        log.debug(String.valueOf(r));
        log.debug("主線程線程結(jié)束");
    }
}

輸出結(jié)果,可以看到這里只是主線程不再等待。

16:28:53.360 c.Test10 [main] - 主線程開始
16:28:54.411 c.Test10 [main] - 11
16:28:54.411 c.Test10 [main] - 主線程線程結(jié)束
16:28:55.404 c.Test10 [線程1] - 線程1結(jié)束

interrupt 方法

interrupt可以用來打斷處于阻塞狀態(tài)的線程。在打斷后,會有一個打斷標記(布爾值)會提示是否被打斷過,被打斷過標記為true否則為false.
但是sleep、wait和join可以來清空打斷標記。

代碼如下

public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");
        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
        log.debug("打斷標記:{}", t1.isInterrupted());
    }

線程被打斷后并不會結(jié)束運行,有人就會問了,那我們?nèi)绾卧诖驍嗑€程后關(guān)閉線程呢?答案就是利用打斷標記去實現(xiàn)。

可以在線程的死循環(huán)之中加入一個判斷去實現(xiàn)。

boolean interrupted = Thread.currentThread().isInterrupted();
                if(interrupted) {
                    log.debug("退出循環(huán)");
                    break;
                }

守護進程

Java 進程通常需要所有線程都運行結(jié)束,才會結(jié)束。

但是存在一種守護進程,只要其他非守護進程結(jié)束,守護進程就會結(jié)束。垃圾回收器就使用的守護進程。

線程的狀態(tài)

操作系統(tǒng)層面(早期進程的狀態(tài))

在這里插入圖片描述

  • 初始狀態(tài) 在語言層面創(chuàng)建了線程對象,還未與操作系統(tǒng)線程關(guān)聯(lián)
  • 可運行狀態(tài)(就緒狀態(tài))指該線程已經(jīng)被創(chuàng)建(與操作系統(tǒng)線程關(guān)聯(lián)),可以由 CPU 調(diào)度執(zhí)行任務(wù)。
  • 運行狀態(tài) 獲取了 CPU 時間片運行中的狀態(tài)
  • 調(diào)用阻塞api使運行狀態(tài)轉(zhuǎn)為阻塞狀態(tài)
  • 終止狀態(tài) 表示線程已經(jīng)執(zhí)行完畢

Java API 層面

在這里插入圖片描述

1、新建狀態(tài)(New)

Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("running...");
            }
        };
log.debug("t1 state {}", t1.getState());

2、就緒狀態(tài)(Runnable)與運行狀態(tài)(Running)

Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                while(true) { // runnable
                }
            }
        };
t2.start();
log.debug("t2 state {}", t2.getState());

3、阻塞狀態(tài)(Blocked)

用一個線程拿到鎖,使得當前線程沒拿到鎖會出現(xiàn)阻塞狀態(tài)。

Thread t6 = new Thread("t6") {
            @Override
            public void run() {
                synchronized (TestState.class) { // blocked
                    try {
                        Thread.sleep(90000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
t6.start();

4、等待狀態(tài)(Waiting)

等待一個未執(zhí)行完成的線程

t2.join(); //等待狀態(tài)

5、超時等待(Time_Waiting)

可以在指定的時間自行返回的。

6、終止狀態(tài)(TERMINATED)

線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。 終止的線程不可再次復(fù)生。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!  

相關(guān)文章

  • SpringBoot 配置文件加密的步驟

    SpringBoot 配置文件加密的步驟

    這篇文章主要介紹了SpringBoot 配置文件加密的步驟,幫助大家更好的理解和學(xué)習(xí)使用springboot框架,感興趣的朋友可以了解下
    2021-03-03
  • spring boot 注入 property的三種方式(推薦)

    spring boot 注入 property的三種方式(推薦)

    這篇文章主要介紹了spring boot 注入 property的三種方式,需要的朋友可以參考下
    2017-07-07
  • Java RabbitMQ的三種Exchange模式

    Java RabbitMQ的三種Exchange模式

    這篇文章主要介紹了Java RabbitMQ的三種Exchange模式,分別為Direct模式、Fanout模式、Topic模式,Rabbit的Direct Exchange模式是指消息發(fā)送導(dǎo)RouteKey中指定的Queue,Direct模式可以使用Rabbit自帶的Exchange
    2022-08-08
  • SpringCloud Nacos配置中心管理超詳細講解

    SpringCloud Nacos配置中心管理超詳細講解

    這篇文章主要介紹了Springcloud中的Nacos服務(wù)配置,本文以用戶微服務(wù)為例,進行統(tǒng)一的配置,結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • 基于spring+quartz的分布式定時任務(wù)框架實現(xiàn)

    基于spring+quartz的分布式定時任務(wù)框架實現(xiàn)

    在Spring中的定時任務(wù)功能,最好的辦法當然是使用Quartz來實現(xiàn)。這篇文章主要介紹了基于spring+quartz的分布式定時任務(wù)框架實現(xiàn),有興趣的可以了解一下。
    2017-01-01
  • Java鏈表的天然遞歸結(jié)構(gòu)性質(zhì)圖文與實例分析

    Java鏈表的天然遞歸結(jié)構(gòu)性質(zhì)圖文與實例分析

    這篇文章主要介紹了Java鏈表的天然遞歸結(jié)構(gòu)性質(zhì),結(jié)合圖文與實例形式分析了java鏈表中遞歸操作的原理、實現(xiàn)技巧與相關(guān)注意事項,需要的朋友可以參考下
    2020-03-03
  • 詳解DES加密算法及在Java程序中的使用示例

    詳解DES加密算法及在Java程序中的使用示例

    這篇文章主要介紹了詳解DES加密算法及在Java程序中的使用示例,文中還有一個用Java實現(xiàn)的DES三重加密的例子,需要的朋友可以參考下
    2016-04-04
  • IDEA中的JFormDesigner使用小結(jié)

    IDEA中的JFormDesigner使用小結(jié)

    JFormDesigner是一款用于設(shè)計和創(chuàng)建圖形用戶界面的插件,本文主要介紹了IDEA中的JFormDesigner使用小結(jié),具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Spring中的MultipartFile詳解

    Spring中的MultipartFile詳解

    這篇文章主要介紹了Spring中的MultipartFile詳解,隨著Spring框架的崛起,使用Spring框架中的MultipartFile來處理文件也是件很方便的事了,今天就為大家?guī)砥饰鯩ultipartFile的神秘面紗,需要的朋友可以參考下
    2024-01-01
  • 詳解SpringBoot啟動類的掃描注解的用法及沖突原則

    詳解SpringBoot啟動類的掃描注解的用法及沖突原則

    這篇文章主要介紹了詳解SpringBoot啟動類的掃描注解的用法及沖突原則,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評論