日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java-进阶:多线程1

發(fā)布時間:2023/11/30 java 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java-进阶:多线程1 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄
一、概述
二、Thread 類
三、創(chuàng)建線程:繼承 Thread 類
四、創(chuàng)建線程:實現(xiàn) Runnable 接口
五、線程優(yōu)先級
六、線程的生命周期
七、同步代碼塊


一、概述

1. 進程和線程

  • 進程:進程指正在運行的程序。
  • 線程:線程是進程中的一個執(zhí)行單元,是程序?使用cpu?的基本單位(調(diào)度)。負責(zé)當前進程中程序的執(zhí)行。是進程中單個順序控制流(執(zhí)行路徑),是一條單獨執(zhí)行的路徑
  • 一個程序運行后至少有一個進程,一個進程中可以包含多個線程
  • 在操作系統(tǒng)中,進程是資源分配的基本單位,線程是調(diào)度的基本單位。

在沒有出現(xiàn)線程之前,進程既是操作系統(tǒng)進行資源分配的基本單位,又是調(diào)度的基本單位

  • 單線程程序:若有多個任務(wù)只能依次執(zhí)行。當上一個任務(wù)執(zhí)行結(jié)束后,下一個任務(wù)開始執(zhí)行。程序只有一條執(zhí)行路徑
  • 多線程程序:若有多個任務(wù)可以同時執(zhí)行。程序有多條執(zhí)行路徑

操作系統(tǒng)發(fā)展:單道批處理操作——>多道批處理操作系統(tǒng)——>分時操作系統(tǒng)(多進程的)——>線程?
批處理:程序在執(zhí)行過程中,不會響應(yīng)用戶的請求?
單道批處理操作:一次只能運行一個程序,如果要在計算機運行多個程序,這多個程序,只能一個一個的順序執(zhí)行,如果這個正在運行的程序,在運行過程中,執(zhí)行了一些非常耗時的IO操作(傳輸數(shù)據(jù)的過程是沒有使用到cpu),這樣一來,cpu就閑下來了,但是cpu是計算機中,最為昂貴的?
多道批處理操作系統(tǒng):同時運行多個程序,顯著的提高了cpu的利用率,但是我們一旦一個,程序運行起來,都是是需要使用計算機資源的?
分時操作系統(tǒng):每一個進程,有一個固定的時間片,在運行一個固定的時間片后,緊接著輪到下一個進程運行(切換)

  • 為什么還會有線程呢??進程切換的代價太高了,這樣一來,每一次進程切換,都需要付出不小的額外的代價,為了減小進程切換的代價,引入了線程,提高CPU的利用率

2. 線程調(diào)度

  • 分時調(diào)度:所有線程?輪流使用?CPU 的使用權(quán),平均分配每個線程占用 CPU 的時間。
  • 搶占式調(diào)度:優(yōu)先讓?優(yōu)先級高的?線程使用 CPU,如果線程的優(yōu)先級相同,那么會隨機選擇一個(線程隨機性),Java使用的為搶占式調(diào)度
  • 體現(xiàn)了:程序運行的不確定性

1. CPU 使用搶占式調(diào)度模式在多個線程間進行著高速的切換。對于CPU的一個核而言,某個時刻,只能執(zhí)行一個線程,而 CPU的在多個線程間切換速度相對我們的感覺要快,看上去就是在同一時刻運行。
2. 多線程程序并不能提高程序的運行速度,但能夠提高程序運行效率,讓CPU的使用率更高。

3. 線程控制

  • 線程睡眠static void sleep(long millis):在指定的毫秒數(shù)內(nèi)讓當前正在執(zhí)行的線程休眠(暫停執(zhí)行)
//讓主線程,休眠3秒 Thread.sleep(3000); //sleep新的寫法 TimeUnit.SECONDS.sleep(3); System.out.println("睡醒了");
  • 線程加入public final void join():(讓當前線程)等待該線程(新加入的線程終止)終止。
SecondThread sec = new SecondThread("zs"); SecondThread thr = new SecondThread("lsii"); SecondThread fou = new SecondThread("wangwu");//啟動這三個線程對象 sec.start(); //sec線程上調(diào)用join方法 ,讓當前線程(main)等待sec線程執(zhí)行完畢 sec.join(); thr.start(); fou.start();
  • 線程禮讓public static void yield():暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程

只是讓當前線程放棄cpu執(zhí)行權(quán),但是不能阻止它放棄后繼續(xù)搶奪cpu執(zhí)行權(quán)

  • 后臺線程(守護線程)public final void setDaemon(boolean on):將該線程標記為守護線程或用戶線程。當正在運行的線程都是守護線程時,Java 虛擬機退出;該方法必須在啟動線程前調(diào)用。
SecondThread sec = new SecondThread("zs"); SecondThread thr = new SecondThread("lsii"); //將sec和thr線程設(shè)置為守護線程 sec.setDaemon(true); thr.setDaemon(true); //啟動 sec.start(); thr.start(); //之后發(fā)現(xiàn)sec和thr是守護線程,就會中斷
  • 中斷線程:public void interrupt():讓一個線程控制另外一個線程(有條件的:受阻),可以利用該方法終止另一個線程的運行

1. 如果線程在調(diào)用 Object 類的 wait()、wait(long) 或 wait(long, int) 方法,或者該類的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 等阻塞方法處于阻塞狀態(tài),它還將收到一個 InterruptedException
2. 中斷一個不處于活動狀態(tài)的線程不需要任何作用。?
中斷一個不處于阻塞狀態(tài)的線程,沒有其他任何效果

public class Test {public static void main(String[] args) {FiveThread fiveThread = new FiveThread();fiveThread.start();//在主線程中,終止fiveThread,休眠狀態(tài)fiveThread.interrupt();} }// 睡5秒之后,再讓該線程輸出一句話 class FiveThread extends Thread{@Overridepublic void run() {try {//假如申請了很多的系統(tǒng)資源TimeUnit.SECONDS.sleep(5);System.out.println("FiveThread 睡醒了");} catch (InterruptedException e) {e.printStackTrace();//異常的意義:即使我的線程被異常終止,我也可以保證資源的正常釋放}} }//會拋出 java.lang.InterruptedException: sleep interrupted

4. JAVA程序的運行原理

  • Java命令會啟動 JVM,即啟動了一個進程,該進程會啟動一個主線程,然后主線程調(diào)用某個類的?main方法,所以 main方法 都是運行在主線程里
  • jvm 啟動后,必然有一個執(zhí)行路徑(線程)從 main方法開始的,一直執(zhí)行到 main方法結(jié)束,這個線程在Java中稱之為主線程。
  • 當程序的主線程執(zhí)行時,如果遇到了循環(huán)而導(dǎo)致程序在指定位置停留時間過長,則無法馬上執(zhí)行下面的程序,需要等待循環(huán)結(jié)束后能夠執(zhí)行
  • 方法在哪個線程中被調(diào)用,它就運行在哪個線程中
  • JVM 是一個多線程程序,每個Java 進程都分配一個 JVM 實例
public class ThreadDemo {public static void main(String[] args) {//利用垃圾回收器來證明while(true) {//這里雖然一直在堆空間中,創(chuàng)建數(shù)組對象,// 但是始終沒有耗盡堆空間,就是因為垃圾回收器,// 在另外一個線程中,幫我們回收垃圾,所以才不會耗盡heap內(nèi)存// 從而證明,jvm是線程的int[] ints = new int[1024];ints = null;}} }

二、Thread 類

1. 概述

  • Thread是程序中的執(zhí)行線程。Java 虛擬機允許應(yīng)用程序并發(fā)地運行多個執(zhí)行線程
  • 不是抽象類

2. 構(gòu)造方法

  • Thread(): 分配新的 Thread 對象
  • Thread(String name):分配新的 Thread 對象,將指定的 name 作為其線程名稱

3. 常用方法

  • void start():使該線程開始執(zhí)行,Java虛擬機調(diào)用線程的 run 方法
  • void run():該線程要執(zhí)行的操作,
  • static void sleep(long millis):在指定毫秒內(nèi)讓當前正在執(zhí)行的線程休眠,暫停執(zhí)行
  • static Thread currentThread():返回當前正在執(zhí)行的線程對象的引用Thread.currentThread()

4. 創(chuàng)建新執(zhí)行線程的兩種方法

  • 將類聲明為?Thread?的子類。該子類應(yīng)重寫 Thread 類的?run?方法。創(chuàng)建對象,開啟線程。run方法相當于其他線程的main方法。
  • 聲明一個實現(xiàn)?Runnable?接口的類。該類然后實現(xiàn)?run?方法。然后創(chuàng)建 Runnable 的子類對象,傳入到某個線程的構(gòu)造方法中,開啟線程。

雖然實現(xiàn)線程有兩種方式,其實從客觀來講,線程本身只代表獨立的執(zhí)行路徑, 執(zhí)行的具體內(nèi)容其實是Task本身,和執(zhí)行路徑的實現(xiàn)本身沒有聯(lián)系;只是我們開發(fā)者,想將一個task放在某條獨立的執(zhí)行路徑(Thread 類對象,也就是一個線程中)來運行


三、創(chuàng)建線程:繼承 Thread 類

  • 創(chuàng)建線程的步驟

  • 定義一個類繼承 Thread

  • 重寫 run方法

  • 創(chuàng)建子類對象,就是創(chuàng)建線程對象

  • 調(diào)用 start 方法,開啟線程并讓線程執(zhí)行,同時還會告訴jvm去調(diào)用 run 方法

線程對象調(diào)用?run方法?不開啟線程。僅是對象調(diào)用方法。?
線程對象調(diào)用?start?開啟線程,并讓 jvm 調(diào)用 run 方法在開啟的線程中執(zhí)行

//測試類 public class Test {public static void main(String[] args) {//創(chuàng)建自定義線程對象MyThread mt = new MyThread("新的線程!");//錯誤啟動線程,這只是普通的方法調(diào)用//firstThread.run();//開啟新線程mt.start();//再次啟動一個線程,會拋異常IllegalThreadStateException //因為一個線程對象只能啟動一次,// 如果同一個線程對象,啟動多次,就會拋出異常//firstThread.start();//只能創(chuàng)建一個新的對象new MyThread("第二個線程!").start();//獲取主線程的名字System.out.println(Thread.currentThread().getName()+":主線程!");} }//自定義線程 class MyThread extends Thread {//定義指定線程名稱的構(gòu)造方法public MyThread(String name) {//調(diào)用父類的String參數(shù)的構(gòu)造方法,指定線程的名稱super(name);}//重寫run方法,完成該線程執(zhí)行的邏輯@Overridepublic void run() {//獲取線程的名字getName()System.out.println(getName() + ":正在執(zhí)行!");} }

四、創(chuàng)建線程:實現(xiàn) Runnable 接口

1. Runnable 接口的構(gòu)造方法

  • Thread(Runnable target): 分配新的 Thread 對象,以便將 target 作為其運行對象
  • Thread(Runnable target,String name)?: 分配新的 Thread 對象,以便將 target 作為其運行對象;并將指定的 name 作為其名稱

2. 創(chuàng)建線程的步驟

  • 定義類實現(xiàn)?Runnable?接口。
  • 覆蓋接口中的?run方法
  • 創(chuàng)建 Thread類的?對象
  • 將 Runnable接口 的子類對象作為參數(shù)傳遞給?Thread 類?的構(gòu)造方法
  • 調(diào)用 Thread類的?start()?開啟線程。

Thread 類的構(gòu)造函數(shù):
1.?Thread(): 分配新的 Thread 對象
2.?Thread(String name):分配新的 Thread 對象,將指定的 name 作為其線程名稱

//測試類 public class Test {public static void main(String[] args) {//創(chuàng)建實現(xiàn) Runnable 接口的子類對象MyRunnable myrunnable = new MyRunnable();//創(chuàng)建Thread實例,在Thread的構(gòu)造方法中傳遞Runnable實例//Runnable就代表在 Thread 上運行的任務(wù)Thread thread = new Thread(myrunnable);//開啟線程thread.start();for (int i = 0; i < 10; i++) {System.out.println("main線程:正在執(zhí)行!"+i);}} }//自定義線程執(zhí)行任務(wù)類 class MyRunnable implements Runnable{//定義線程要執(zhí)行的run方法邏輯//run方法,不能拋出編譯時異常//run方法,沒有參數(shù)沒有返回值@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("我的線程:正在執(zhí)行!"+i);}} }

3. 實現(xiàn) Runnable 接口的原理

為什么需要定一個類去實現(xiàn)Runnable接口呢?繼承Thread類和實現(xiàn)Runnable接口有啥區(qū)別呢??
只有創(chuàng)建Thread類的對象才可以創(chuàng)建線程。線程任務(wù)已被封裝到Runnable接口的run方法中,而這個run方法所屬于Runnable接口的子類對象,所以將這個子類對象作為參數(shù)傳遞給Thread的構(gòu)造函數(shù),這樣,線程對象創(chuàng)建時就可以明確要運行的線程的任務(wù)

4. 兩種方式的比較

  • 繼承 Thread 類方式

  • 如果某個類已經(jīng)有父類,則無法再繼承 Thread 類

  • 實現(xiàn) Runnable 接口方式

  • 解決了方式一的單繼承的局限性

  • 還有一個優(yōu)點,便于多線程共享數(shù)據(jù)

第二種方式實現(xiàn)Runnable接口避免了單繼承的局限性,所以較為常用。實現(xiàn)Runnable接口的方式,更加的符合面向?qū)ο?#xff1b;線程分為兩部分,一部分線程對象,一部分線程任務(wù)。

  • 繼承Thread類,線程對象和線程任務(wù)耦合在一起。一旦創(chuàng)建Thread類的子類對象,既是線程對象,有又有線程任務(wù)
  • 實現(xiàn)runnable接口,將線程任務(wù)單獨分離出來封裝成對象類型就是Runnable接口類型。Runnable接口對線程對象和線程任務(wù)進行解耦

五、線程優(yōu)先級

1. 概述

  • 我們可以通過?Thread?類中:

  • getPriority 方法?:獲取?線程的優(yōu)先級

  • setPriority 方法?:設(shè)置?線程的優(yōu)先級

2. 線程優(yōu)先級的范圍

  • 如果設(shè)置線程優(yōu)先級的范圍,超出了規(guī)定范圍,會拋出異常;

MAX_PRIORITY 10 //最大優(yōu)先級?
MIN_PRIORITY 1 //最小優(yōu)先級?
NORM_PRIORITY 5 //默認優(yōu)先級

//使用 thread1.setPriority(Thread.MAX_PRIORITY); //設(shè)置 thread2.setPriority(Thread.MIN_PRIORITY); System.out.println(thread1.getPriority());//獲取

3. 注意!

  • 對于 TThread 類中的優(yōu)先級,對于jvm而言,不起決定性作用

也就是說 jvm 在實際調(diào)度線程的時候,它使用的優(yōu)先級可能不僅僅包含我們給每個線程所設(shè)置的靜態(tài)優(yōu)先級,可能還考慮了其他的很多因素(各個線程的運行狀態(tài)),所以我們所設(shè)置的優(yōu)先級對于 jvm 只起一個參考作用


六、線程的生命周期

1. 新建狀態(tài)

  • 創(chuàng)建線程對象

2. 就緒狀態(tài)

  • ?start() 之后
  • sleep() 睡醒之后
  • yield() 之后
  • 有執(zhí)行資格,等待cpu調(diào)度

3. 運行狀態(tài)

  • 取得執(zhí)行權(quán),開始執(zhí)行

4. 阻塞狀態(tài)

  • 無執(zhí)行資格,無執(zhí)行權(quán)

5. 死亡狀態(tài)

  • 執(zhí)行完畢,等待垃圾回收


七、同步代碼塊

1. 問題引入——線程安全問題

  • 發(fā)生線程安全問題的三個條件

1. 多線程運行環(huán)境
2. 多線程訪問線程共享數(shù)據(jù)(存在共享數(shù)據(jù))
3. 訪問共享數(shù)據(jù)的操作不是原子操作。?
注:原子操作:不可分割的操作?,相當于一次性完成的操作

  • 當這三個條件同時滿足的時候,才會發(fā)生多線程的數(shù)據(jù)安全問題
  • 解決多線程的線程安全問題:如何實現(xiàn)線程對共享資源的排他性訪問(只有我訪問完了你們才能修改)?
  • 使用?同步代碼塊

2. 同步代碼塊

  • 同步代碼塊實現(xiàn)?線程同步
  • 線程同步:就是利用鎖對象,完成多線程運行環(huán)境中,對共享資源的排他性訪問(我走你不能走, 你走我不能走)
  • 優(yōu)點:解決了多線程的安全問題
  • 缺點:消耗資源(當線程很多時,每個線程運行的時候都需要去判斷同步鎖,這個是很耗費系統(tǒng)資源的)

線程異步:線程之間,互不干擾,各自獨立運行(我走我的,你走你的)

  • 格式
synchronized(對象){//critical section對共享資源的訪問的代碼 }

1. 同步代碼塊中所使用的對象,稱之為鎖對象?——> 鎖的角色?
鎖對象中,有一個標志位:可以表示兩種狀態(tài),加鎖?和?解鎖
2. 持有鎖的是線程(一個線程給一個鎖對象加鎖,我們就說這個線程持有了鎖對象)
3. 同步代碼塊何時給鎖對象加鎖?進入同步代碼塊的同時,就給鎖對象加鎖
4. 線程何時釋放持有的鎖??當執(zhí)行完同步代碼塊的時候,就會釋放同步代碼塊的鎖對象
5. 判斷和修改鎖對象
標志位
的操作,這是由 jvm?保證一定是原子操作?
6.**?鎖對象,究竟是什么對象**? java語言中任意一個對象,都可以充當鎖對象的角色(因為任意一個對象中都有一個表示加鎖,解鎖狀態(tài)的標志位)

  • 注意點

雖然鎖對象可以是任意對象,但是針對同一個(同樣的多個共享變量)?的所有操作,都必須保證在同步代碼塊中,使用同一個鎖對象,才能避免線程安全問題。

3. 同步方法

  • 當同步代碼塊的范圍擴大到整個方法的方法體的時候,我們可以將整個方法定義成同步方法,在方法聲明上加上synchronized
  • 普通的同步代碼塊:?synchronized(鎖對象) {}
  • 同步方法:?void synchronized 方法名(){}
  • 同步方法的鎖對象就是?this

靜態(tài)方法是否可以定義為同步方法??
靜態(tài)的同步方法, 在方法聲明上加上static synchronized?
**,都可以充當鎖對象的角色(因為任意一個對象中都有一個表示加鎖,解鎖狀態(tài)的標志位)

  • 注意點

雖然鎖對象可以是任意對象,但是針對同一個(同樣的多個共享變量)?的所有操作,都必須保證在同步代碼塊中,使用同一個鎖對象,才能避免線程安全問題。

3. 同步方法

  • 當同步代碼塊的范圍擴大到整個方法的方法體的時候,我們可以將整個方法定義成同步方法,在方法聲明上加上synchronized
  • 普通的同步代碼塊:?synchronized(鎖對象) {}
  • 同步方法:?void synchronized 方法名(){}
  • 同步方法的鎖對象就是?this

靜態(tài)方法是否可以定義為同步方法??
靜態(tài)的同步方法, 在方法聲明上加上static synchronized

總結(jié)

以上是生活随笔為你收集整理的Java-进阶:多线程1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。