線程 Thread 進程: 正在進行的程式 一個進程中至少有一個線程 進程是系統進行資源分配和調用的獨立單位,每一個進程都有它自己的記憶體空間和系統資源 多進程:可以同時乾很多事情,但不是同時進行,而是在程式間高效切換。 線程:在同一個進程中可以執行多個任務,而每一個任務,就是一個線程,是程式的執行單 ...
線程 Thread 進程: 正在進行的程式 一個進程中至少有一個線程 進程是系統進行資源分配和調用的獨立單位,每一個進程都有它自己的記憶體空間和系統資源 多進程:可以同時乾很多事情,但不是同時進行,而是在程式間高效切換。 線程:在同一個進程中可以執行多個任務,而每一個任務,就是一個線程,是程式的執行單元,執行路徑,是程式使用cpu的最基本單位。 單線程:程式只有一條執行路徑 多線程:程式有多條執行路徑 多線程存在的意義:不是提高程式的執行速度,而是為了提高應用程式的使用率。 併發:一個處理器同時處理多個任務(邏輯上的同時發生) 並行:多個處理器或是多核的處理器同時處理多個不同的任務 (物理上的同時發生) Java 程式的運行原理: 由Java命令啟動JVM,JVM啟動就相當於啟動了一個進程。 接著由該進程創建了一個主線程去調用 main 方法。 JVM 虛擬機的啟動是單線程的還是多線程的? 多線程的。 原因是垃圾回收線程也要先啟動,否則很容易會出現記憶體溢出。 現在的垃圾回收線程加上前面的主線程,最低啟動了兩個線程,所以,JVM的啟動其實是多線程的。
線程的生命周期: 新建:創建一個線程對象 就緒:調用 start()方法後,線程有執行資格,但沒有獲取到執行權(也就是沒有獲取到CPU記憶體資源) 運行:獲取到執行權(獲取到CPU記憶體資源) 阻塞:沒有執行資格也沒有執行權,一般是調用方法 suspend()、sleep()、wait()、join()方法後線程進入阻塞狀態 死亡:run()方法結束,或線程被中斷(調用方法stop()或destroy()) 如何實現多線程: 方式1:繼承 Thread 類 A:自定義類 MyThread 繼承 Thread 類。 B:MyThread 類裡面重寫 run()。 C:創建對象。 D:啟動線程 使用 start()方法。 方式2:實現 Runnable 介面 A:自定義類 MyRunnable 實現 Runnable 介面 B:重寫 run()方法 C:創建 MyRunnable 類的對象 D:創建 Thread 類的對象,並把MyRunnable 類的對象作為構造參數傳遞 兩種實現線程的方法的區別: 實現 Runnable 介面可以避免 Java 中單一繼承的局限性; 適合多個相同程式的代碼去處理同一個資源的情況,把線程同程式代碼數據有效的分離。 增加程式的健壯性,代碼可以被多個線程共用,代碼和數據獨立。 繼承 Thread : 線程代碼存放在 Thread 子類run()方法中。 實現 Runnable : 線程代碼存放在 Runnable 介面的子類的run()方法中。
一個線程只能調用一次 start()方法,如果調用多次會出現:IllegalThreadStateException 非法的線程狀態異常 題1:為什麼要重寫run()方法? 答:不是類中的所有代碼都需要被線程執行的。 而在這個時候,為了區分哪些代碼能夠被線程執行,Java提供了 Thread類中的run()方法用來包含那些被線程執行的代碼。 Thread 類中的 run()方法,是用於存儲線程要運行的代碼。 覆寫run()方法的目的:將自定義代碼存儲在run ()方法中,讓線程運行。 題2:run()和 start()的區別? 答:run():僅僅是封裝被線程執行的代碼,直接調用是普通方法。僅僅是對象調用方法,而線程創建了卻並沒有執行。 start():首先啟動了線程,然後再由 JVM去調用該線程的 run()方法。開啟線程並執行該線程的run()方法 多線程安全問題的原因(判斷一個程式是否有線程安全問題的依據): A:是否有多線程環境 B:是否有共用數據 C:是否有多條語句操作共用數據 同步的前提: ① 必須要有兩個或者兩個以上的線程 ② 必須是多個線程使用同一鎖 ③ 必須保證同步中只能有一個線程在運行 好處:解決了多線程的安全問題 弊端:多個線程需要判斷鎖,較為消耗資源 線程同步: ① 線程同步就是線程排隊 ② 只有共用資源的讀寫訪問才需要同步 ③ 只有變數才需要同步訪問 ④ 多個線程訪問共用資源的代碼有可能是同一份代碼,也有可能是不同的代碼。 解決線程安全問題: A:同步代碼塊: synchronized(對象){ 需要被同步的代碼; } 這裡鎖的對象是任意對象 B:同步方法 把同步加在方法上。 這裡的鎖對象是 this。 C:靜態同步方法 把同步加在靜態方法上 這裡的鎖對象是 當前類的位元組碼文件對象 文件名.class 同一個對象共用數據不需要加 static,多個不同對象共用數據要加 static 多線程有幾種實現方案,分別是哪幾種? 答:兩種 繼承 Thread 類,實現 Runnable 介面 擴展一種:實現 Callable 介面和線程池結合。重寫 call()方法 同步有幾種方式?分別是什麼? 同步代碼塊,同步方法,同步靜態方法 sleep()和 wait()方法的區別: sleep():必須指時間;不釋放鎖 wait():可以不指定時間,也可以指定時間;釋放鎖 為什麼wait(),notify(),notifyAll()等方法都定義在 Object 類中? 因為這些方法都調用是依賴於鎖對象的,而同步代碼塊的鎖對象是任意鎖。 而 Object 代表任意的對象,所以,定義在這裡面。 當一個線程進入一個對象的一個synchronized方法後,其它線程是否可進入此對象的其它方法? 分幾種情況: 1.其他方法前是否加了synchronized關鍵字,如果沒加,則能。 2.如果這個方法內部調用了wait,則可以進入其他synchronized方法。 3.如果其他個方法都加了synchronized關鍵字,並且內部沒有調用wait,則不能。 4.如果其他方法是static,它用的同步鎖是當前類的位元組碼,與非靜態的方法不能同步,因為非靜態的方法用的是this。 簡述synchronized和java.util.concurrent.locks.Lock的異同? 主要相同點:Lock能完成synchronized所實現的所有功能 主要不同點:Lock有比synchronized更精確的線程語義和更好的性能。 synchronized會自動釋放鎖,而Lock一定要求程式員手工釋放,並且必須在finally從句中釋放。 守護線程:也叫精靈線程、後臺線程 特點: A : 不具備生命周期,它隨著虛擬機的結束而結束 B : 如果想把線程轉換成精靈線程,必須在start()之前調用 setDaemon(boolean)方法 一旦線程變為精靈線程就不能變為用戶線程了。 守護線程和用戶線程的區別: 守護線程是無生命周期的,伴隨著用戶線程存在,如果用戶線程執行完畢,守護線程還沒有執行完畢, 那麼守護線程也將結束,守護線程線上程啟動前調用,setDaemon(true) 線程池: 根據自身的環境情況,有效的限制執行線程的數量,使得運行效果達到最佳。 線程池的作用: 減少創建和銷毀線程的次數,每個工作線程可以多次使用 可根據系統情況調整執行的線程數量,防止消耗過多記憶體。 使用: ExecutorService pool = Executors.常見線程池; 常見線程池: ①newSingleThreadExecutor : 創建一個單線程的線程池 ②newFixedThreadExecutor(n) : 創建固定大小的線程池 ③newCacheThreadExecutor(推薦使用) : 創建一個可緩存的線程池 ④newScheduleThreadExecutor : 大小無限制的線程池,支持定時和周期性的執行線程 1.線程同步的目的是為了保護多個線程訪問一個資源時對資源的破壞。 2.線程同步方法是通過鎖來實現的,每個對象都有且僅有一個鎖,這個鎖與一個特定的對象關聯,線程一旦獲取了對象鎖, 其他訪問該對象的線程就無法再訪問該對象的其他同步方法。 3.對於靜態同步方法,鎖是針對這個類的,鎖對象是該類的Class對象。文件名.class 靜態和非靜態方法的鎖互不幹預。 一個線程獲得鎖,當在一個同步方法中訪問另外對象上的同步方法時,會獲取這兩個對象鎖。 4.對於同步,要時刻清醒在哪個對象上同步,這是關鍵。 5.編寫線程安全的類,需要時刻註意對多個線程競爭訪問資源的邏輯和安全作出正確的判斷, 對"原子"操作作出分析,並保證原子操作期間別的線程無法訪問競爭資源。 6.當多個線程等待一個對象鎖時,沒有獲取到鎖的線程將發生阻塞。 7.死鎖是線程間相互等待鎖造成的,在實際中發生的概率非常的小。 線程組(ThreadGroup): 是指 java.lang.ThreadGroup 類的對象 線程組與線程池的區別: ①線程組存在的意義,首要原因是 安全。 java預設創建的線程都是屬於系統線程組,而同一個線程組的數據是可以相互修改對方的數據的。 線程組除安全外,最有用的一個地方就是 控制,只需用單個命令即可完成對整個線程組的操作。 ②線程池存在的意義,首要作用是 效率。 線程的創建和結束都需要耗費一定的系統時間,不停創建和刪除線程會浪費大量的時間, 所以,在創建出一條線程並使其在執行完任務後不結束,而是使其進入休眠狀態,在需要用時再喚醒, 那麼 就可以節省一定的時間 線程組和線程池共有的特點: 1. 都是管理一定數量的線程 2. 都可以對線程進行控制---包括休眠,喚醒,結束,創建,中斷(暫停)--但並不一定包含全部這些操作。