java-多執行緒與并發
以下內容為本人的學習筆記,如需要轉載,請宣告原文鏈接 https://www.cnblogs.com/lyh1024/p/16786357.html
多執行緒
1.行程與執行緒
1.1 什么是行程
程式是指令和資料的有序集合,其本身沒有任何運行的含義,是一個靜態的概念,而行程是程式在處理機上的一次執行程序,它是一個動態的概念,
行程是一個具有一定獨立功能的程式,一個物體,每一個行程都有它自己的地址空間,
1.2 行程的狀態
行程執行時的間斷性,決定了行程可能有多種狀態,事實上,運行中的行程具有以下三種基本狀態,
-
就緒狀態(Ready)
-
運行狀態(Running)
-
阻塞狀態(Blocked)

cpu是有轉速的,轉速越快,性能越高,但CPU運行a程式時,要轉到h程式,需要時間,這時候行程就會進入阻塞狀態,

1.3 執行緒
執行緒實際上是在行程基礎上調度進一步劃分,一個執行緒啟動后,里面的若干程式又可以劃分成若干個執行緒,
執行緒:是行程中的一個執行路徑,共享一個記憶體空間,程式之間可以自由切換,并發執行,一個行程最少有一個執行緒(單執行緒程式)
一個程式可以同時執行多個任務,來提高效率
例如:①同時下載多部電影
②看電影的同時吃零食
并行:就是兩個任務同時運行(多個CPU)
并發:是指兩個任務同時請求運行,而處理器一次只能接受一個任務,就會把兩個任務安排輪流執行,由于CPU時間片運行時間較短,就會感覺是兩個任務在同時執行
-
面試題:行程和執行緒的區別?
2.執行緒的基本使用
執行緒實作的三種方式
在java中如果要想實作多執行緒的操作,有兩種實作方法:
1)繼承Thread類(只能繼承一個)
2)實作Runnable介面(建議使用,可以實作多個)
3)實作Callable介面
public class ThreadDeom1{
public static void main(String[] args){
MyThread mt = new Thread();
MyRunnable mr = new MyRunnable();
Thread t2 = new Thread(mr);//將實作Runnable的當成一個任務放進執行緒Thread里
mt.start();//啟動執行緒,(實際是,start表準備就緒,告訴虛擬機可以啟動執行緒)
t2.start();//可簡寫,合并成:new Thread(mr).start
}
}
?
/**
創建執行緒方式一:
1.繼承Thread類
2.重寫run()方法
3.創建執行緒物件,呼叫start()開啟執行緒
注意:執行緒開啟不一定立即執行,有CPU調度執行
*/
class MyThread extends Thread{
public void run(){
for(int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"-"+i);
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
?
/**
創建執行緒方式二:
1.實作Runnable介面
2.重寫run()方法
3.創建Runnable介面的實作類物件
4.創建執行緒物件(代理),丟入實作類物件
5.呼叫start()開啟執行緒
注意:執行緒開啟不一定立即執行,有CPU調度執行
*/
class MyRunnable implement Runnable{
public void run(){
for(int i = 0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"-"+i);
try{
/**
執行緒的休眠
在當前執行緒的執行中,暫停指定的毫秒數,釋放CPU的時間片
釋放CPU的時間片意思:CPU給一個行程P ,3秒執行時間,執行緒A和執行緒B互搶這個3秒時間片,設A搶到了,執行了3秒,此時會中斷,然后CPU執行下一個行程,CPU一直轉,又轉到行程P,然后A和B又開始互搶這3秒時間片,A又搶到,繼上次中斷的位置開始執行,執行完后,就讓時間片給其他執行緒,
*/
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
/**
創建執行緒方式三:
1.實作Callable介面,需要回傳值型別
2.重寫call方法,需要拋出例外
3.創建目標物件
4.創建執行服務:ExecutorService ser = Exectors.newFixedThreadPool(1);
5.提交執行:Future<Boolean> result1 = ser.submit(t1);
6.獲取結果:boolean r1 = result1.get();
7.關閉服務:ser.shutdownNow();
*/
案例:



3.執行緒的休眠
public static void sleep(long millis) throws InterruptedException
使當前正在執行的執行緒以指定的毫秒數暫停(暫時停止執行),釋放CPU的時間片,具體取決于系統定時器和調度程式的精度和準確性, 執行緒不會丟失任何顯示幕的所有權,
-
引數
millis- 以毫秒為單位的睡眠時間長度 -
例外
IllegalArgumentException- 如果millis值為負數InterruptedException- 如果任何執行緒中斷當前執行緒, 當拋出此例外時,當前執行緒的中斷狀態將被清除, 由執行緒本身中斷不會報錯,
-
執行緒的休眠,目的是讓出CPU執行的時間片,讓其他作業的執行緒可以執行,但不會釋放物件鎖
-
sleep可以模擬網路延遲,倒計時等
-
sleep時間達到后執行緒進入就緒狀態
public static void sleep(long millis,int nanos) throws InterruptedException//毫秒,納秒
public static Thread currentThread()//回傳對當前正在執行的執行緒物件的參考,即獲取當前執行緒
4.join與中斷執行緒
public final void join() throws InterruptedException
等待這個執行緒死亡,
呼叫此方法的行為方式與呼叫join(0) 完全相同
-
例外
InterruptedException- 如果任何執行緒中斷當前執行緒, 當拋出此例外時,當前執行緒的中斷狀態將被清除,
| public void interrupt() | 中斷這個執行緒, 除非當前執行緒中斷自身,這是始終允許的 |
| public static boolean interrupted() | 測驗當前執行緒是否中斷, 該方法可以清除執行緒的中斷狀態 , 換句話說,如果這個方法被連續呼叫兩次,那么第二個呼叫將回傳false(除非當前執行緒再次中斷,在第一個呼叫已經清除其中斷狀態之后,在第二個呼叫之前已經檢查過), 忽略執行緒中斷,因為執行緒在中斷時不存在將被該方法回傳false所反映, |
join方法的主要作用就是同步,它可以使得執行緒之間的并行執行變為串行執行
或者說 join合并執行緒,待此執行緒執行完畢后,回去再執行其他執行緒,其他執行緒阻塞,可以想象成插隊
public class ThreadDeom2{
public static void main(String[] args){
MyRunnable mr2 = new MyRunnable2();
Thread t1 = new Thread(mr2);
MyRunnable mr3 = new MyRunnable3();
?
Thread t2 = new Thread(mr3);
t1.start();
t2.start();
for(int i = 0;i<50;i++){
System.out.println(Thread.currentThread().getName()+"-"+i);
try{
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
}
if(i==20){
/** try{
t1.join();//讓t執行緒執行完畢
}catch (InterruptedException e){
e.printStackTrace();
}*/
// t1.interrupt();//中斷執行緒(不會真的中斷執行緒),只是作了一個中斷標記
mr3.flag =false;
}
}
}
}
?
class MyRunable2 implements Runnable{
public void run(){
for(int i = 0;i<50;i++){
/**
中斷執行緒方式一:
1.使用interrupt()來中斷執行緒,設定一個中斷狀態(標記)
2.run方法里測驗中斷狀態Thread.interrupted()
3.有sleep等拋出InterruptedException例外的,要重新打上中斷標記
中斷執行緒方式二(更加推薦使用):
1.自定義標記的方式,設定一個布林值為ture,作為while的條件,要中斷時就將該布林值設為false
*/
if(Thread.interrupted()){//測驗中斷狀態,此方法會把中斷狀態清除
break;//不會真的中斷,因為sleep會拋出InterruptedException例外并把中斷標記清除,所以要重新打上中斷標記
}
System.out.println(Thread.currentThread().getName()+"-"+i);
try{
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
Thread.currentThread().interrupt();//重新打上中斷標記
}
}
}
}
?
class MyRunable3 implements Runnable{
public boolean flag = true;
public MyRunable3(){
flag = true;
}
public void run(){
int i = 0;
while(flag){
System.out.println(Thread.currentThread().getName()+"---"+i);
try{
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
5.守護執行緒與yield
執行緒分為用戶執行緒和守護執行緒
虛擬機必須確保用戶執行緒執行完畢
虛擬機不用等待守護執行緒執行完畢(用戶執行緒執行完畢后,JVM虛擬機自動退出,不用等待守護執行緒執行完畢)
如,后臺記錄操作日志,監控記憶體,垃圾回收等待....
| method | 說明 |
|---|---|
| public final void setDaemon(boolean on) | 將此執行緒標記為daemon執行緒或用戶執行緒, 當運行的唯一執行緒都是守護行程執行緒時,Java虛擬機將退出, |
| public final boolean isDaemon() | 測驗這個執行緒是否是守護執行緒, |
| public static void yield() | 暫停當前正在執行的執行緒物件,并執行其他執行緒(了解) |
yield作用是暫停當前正在執行的執行緒物件(放棄當前CPU資源),并執行其他執行緒,
yield是讓當前運行執行緒回到可運行狀態,以允許具有相同優先級的其他執行緒獲得運行機會
補充:當原始碼有native修飾,表示為本地方法,有c或c++實作
for(int i = 0;i<50;i++){
System.out.println(Thread.currentThread().getName()+"-"+i);
try{
Thread.sleep(300);
}catch (InterruptedException e){
e.printStackTrace();
}
if(i==5){
Thread.yield();//讓出本次CPU執行時間片,就讓一次,下一次還搶CPU時間片
}
}
6.其他方法與優先級
| Method or Fieids | 說明 |
|---|---|
long getId() |
回傳此執行緒的識別符號, |
String getName() |
回傳此執行緒的名稱, |
int getPriority() |
回傳此執行緒的優先級, |
boolean isAlive() |
測驗這個執行緒是否處于活動狀態,start以后就是活動狀態, |
void setName(String name) |
將此執行緒的名稱更改為等于引數 name , |
More Actionsvoid``setPriority(int newPriority) |
更改此執行緒的優先級, |
static int MAX_PRIORITY |
執行緒可以擁有的最大優先級, |
static int ``MIN_PRIORITY |
執行緒可以擁有的最小優先級, |
static int NORM_PRIORITY |
分配給執行緒的默認優先級, |
有待補充......
參考資料:
JDK1.8幫助檔案
2022-10-12 22:22:12
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/514059.html
標籤:Java
上一篇:Java圖形化學生管理(一)
