你知道什么是JUC了嗎?


多線程一直Java開發中的難點,也是面試中的常客,趁着還有時間,打算鞏固一下JUC方面知識,我想機會隨處可見,但始終都是留給有准備的人的,希望我們都能加油!!!

沉下去,再浮上來,我想我們會變的不一樣的。

一、JUC簡介

JUC實際上就是我們對於jdk中java.util .concurrent 工具包的簡稱。這個包下都是Java處理線程相關的類,自jdk1.5后出現。

在這里插入圖片描述

二、進程與線程

2.1、進程

概述:

進程(Process) 是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。 在當代面向線程設計的計算機結構中,進程是線程的容器程序是指令、數據及其組織形式的 描述進程是程序的實體

定義:

狹義定義:進程是正在運行的程序的實例(an instance of a computer program that is being executed)。

廣義定義:進程是一個具有一定獨立功能的程序關於某個數據集合的一次運行活動。它是操作系統動態執行的基本單元,在傳統的操作系統中,進程既是基本的分配單元,也是基本的執行單元。

2.2、線程

線程(thread) 是操作系統能夠進行運算調度的最小單位。它被包含在進程之 中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流, 一個進程中可以並發多個線程,每條線程並行執行不同的任務

1、線程是獨立調度和分派的基本單位。2、同一進程中的多條線程將共享該進程中的全部系統資源。3、一個進程可以有很多線程,每條線程並行執行不同的任務。可並發執行。

當然,我們Java都知道的線程的同步是Java多線程編程的難點,因為要給哪些地方是共享資源(競爭資源),什么時候要考慮同步等,都是編程中的難點。😭所以才有了那么多滴鎖,看到煩人。

2.3、創建線程的三種常見方式

  1. 通過實現Runnable接口來創建Thread線程
public class TheardCreateDemo {

    public static void main(String[] args) {
        Runnable runnable = new SomeRunnable();
        Thread thread1 = new Thread(runnable);
        thread1.start();
        //lamda表達式方式
        Thread thread2 = new Thread(() -> {
            System.out.println("使用lamda表達式方式");
        });
        thread2.start();
    }
}
class SomeRunnable implements Runnable
{
    @Override
    public void run()
    {
        System.out.println(Thread.currentThread().getName()+":: 通過實現Runnable接口來創建Thread線程");
    }
}

2.通過繼承Thread類來創建一個線程

public class TheardCreateDemo {

    public static void main(String[] args) {
        SomeThread thread = new SomeThread();
        thread.start();
    }
}

class SomeThread extends Thread{
    @Override
    public void run() {
        System.out.println("通過繼承Thread類來創建一個線程");
    }
}

3.通過實現Callable接口來創建Thread線程

public class TheardCreateDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        
        FutureTask<Object> futureTask = new FutureTask<Object>(new SomeCallable<Object>());
        Thread oneThread = new Thread(futureTask);
        
        oneThread.start();
        // 這里可以在運行之后獲得 返回值
        System.out.println(futureTask.get());
    }
}

class SomeCallable<Object> implements Callable<Object> {
    @Override
    public Object call() throws Exception {
        System.out.println("通過實現Callable接口來創建Thread線程");
        // 這個是可以返回數據的 這里就隨便返回個 1024 哈
        return (Object)" 這個是可以返回數據的 這里就隨便返回個哈";
    }
}

這里之后有篇文章還會講到這個點的。

這里稍微講下步驟:

}
步驟1:創建實現Callable接口的類SomeCallable

步驟2:創建一個類對象:Callable oneCallable = new SomeCallable ();

步驟3:由Callable 創建一個FutureTask 對象:

FutureTask futureTask= new FutureTask (oneCallable);

注釋:FutureTask 是一個包裝器,它通過接受Callable 來創建,它同時實現了Future和Runnable接口。
步驟4:由FutureTask 創建一個Thread對象:Thread oneThread = new Thread(futureTask);

步驟5:啟動線程:oneThread.start();

這里為什么Thread(FutureTask futureTask)可以勒?

Thread的構造函數:

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

原因:因為套娃套到一起啦。😁

public class FutureTask<V> implements RunnableFuture<V> 
    
public interface RunnableFuture<V> extends Runnable, Future<V> 

線程池的創建方式之后有一章會講到,就不在此處增加篇幅啦。

三、並發和並行

在了解並發和並行之前,讓我們先來看一看串行是什么樣的吧。

1)串行模式:

串行模式:即表示所有任務都是按先后順序進行。串行是一次只能取的一個任務,並執行這個任務。

舉個生活中的小例子:就是在火車站買票,今天只開放這一個窗口賣票,那么我們只有等到前面的人都買了,才能輪到我們去買。即按先后順序買到票。

2)並行模式:

概述:一組程序按獨立異步的速度執行,無論從微觀還是宏觀,程序都是一起執行的。對比地,並發是指:在同一個時間段內,兩個或多個程序執行,有時間上的重疊(宏觀上是同時,微觀上仍是順序執行)。

並行模式:並行意味着可以同時取得多個任務,並同時去執行所取得的這些任務。

我們還是用上面那個例子:還是在買票,以前是只有一個窗口賣票,但是近幾年發展起來了,現在有五個窗口賣票啦,大大縮短了人們買票的時間。

並行模式相當於將長長的一條隊列,划分成了多條短隊列,所以並行縮短了任務隊列的長度。不過並行的效率,一方面受多進程/線程編碼的好壞的影響,另一方面也受硬件角度上的CPU的影響。

3)並發:

並發並發指的是多個程序可以同時運行的一種現象,並發的重點在於它是一種現象,並發描述的是多進程同時運行的現象。但真正意義上,一個單核心CPU任一時刻都只能運行一個線程。所以此處的"同時運行"表示的不是真的同一時刻有多個線程運行的現象(這是並行的概念),而是提供了一種功能讓用戶看來多個程序同時運行起來了,但實際上這些程序中的進程不是一直霸占 CPU 的,而是根據CPU的調度,執行一會兒停一會兒。

4)小小的總結一下:

並發:即同一時刻多個線程在訪問同一個資源,多個線程對一個點

  • 例子:秒殺活動、12306搶回家的票啦、搶演唱會的票...

並行:多個任務一起執行,之后再匯總

  • 例子:電飯煲煮飯、用鍋炒菜,兩個事情一起進行,(最后我們一起干飯啦干飯啦😁)

四、用戶線程和守護線程

用戶線程:指不需要內核支持而在用戶程序中實現的線程,其不依賴於操作系統核心,應用進程利用線程庫提供創建、同步、調度和管理線程的函數來控制用戶線程。

守護線程是指在程序運行的時候在后台提供一種通用服務的線程,用來服務於用戶線程;不需要上層邏輯介入,當然我們也可以手動創建一個守護線程。(用白話來說:就是守護着用戶線程,當用戶線程死亡,守護線程也會隨之死亡)

比如垃圾回收線程就是一個很稱職的守護者,並且這種線程並不屬於程序中不可或缺的部分。因此,當所有的非守護線程結束時,程序也就終止了,同時會殺死進程中的所有守護線程。反過來說,只要任何非守護線程還在運行,程序就不會終止。

用一個簡單代碼來模擬一下:

未設置為守護線程時:主線程執行完成了,但是我們自己創建的線程仍然未結束。

在這里插入圖片描述

設置為守護線程后:明顯可以看到,當主線程執行完成后,我們設置為守護線程的那個線程也被強制結束了。

在這里插入圖片描述

setDaemon就是設置為是否為守護線程。

五、自言自語

最近又開始了JUC的學習,感覺Java內容真的很多,但是為了能夠走的更遠,還是覺得應該需要打牢一下基礎。

最近在持續更新中,如果你覺得對你有所幫助,也感興趣的話,關注我吧,讓我們一起學習,一起討論吧。

你好,我是博主寧在春,Java學習路上的一顆小小的種子,也希望有一天能扎根長成蒼天大樹。

希望與君共勉😁

待我們,別時相見時,都已有所成


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM