java進階05多線程的簡單介紹

本文目錄一覽:

什麼是JAVA的多線程?

一、 什麼是多線程:

我們現在所使用操作系統都是多任務操作系統(早期使用的DOS操作系統為單任務操作系統),多任務操作指在同一時刻可以同時做多件事(可以同時執行多個程序)。

多進程:每個程序都是一個進程,在操作系統中可以同時執行多個程序,多進程的目的是為了有效的使用CPU資源,每開一個進程系統要為該進程分配相關的系統資源(內存資源)

多線程:線程是進程內部比進程更小的執行單元(執行流|程序片段),每個線程完成一個任務,每個進程內部包含了多個線程每個線程做自己的事情,在進程中的所有線程共享該進程的資源;

主線程:在進程中至少存在一個主線程,其他子線程都由主線程開啟,主線程不一定在其他線程結束後結束,有可能在其他線程結束前結束。Java中的主線程是main線程,是Java的main函數;

二、 Java中實現多線程的方式:

繼承Thread類來實現多線程:

當我們自定義的類繼承Thread類後,該類就為一個線程類,該類為一個獨立的執行單元,線程代碼必須編寫在run()方法中,run方法是由Thread類定義,我們自己寫的線程類必須重寫run方法。

run方法中定義的代碼為線程代碼,但run方法不能直接調用,如果直接調用並沒有開啟新的線程而是將run方法交給調用的線程執行

要開啟新的線程需要調用Thread類的start()方法,該方法自動開啟一個新的線程並自動執行run方法中的內容

結果:

java多線程的啟動順序不一定是線程執行的順序,各個線程之間是搶佔CPU資源執行的,所有有可能出現與啟動順序不一致的情況。

CPU的調用策略:

如何使用CPU資源是由操作系統來決定的,但操作系統只能決定CPU的使用策略不能控制實際獲得CPU執行權的程序。

線程執行有兩種方式:

1.搶佔式:

目前PC機中使用最多的一種方式,線程搶佔CPU的執行權,當一個線程搶到CPU的資源後並不是一直執行到此線程執行結束,而是執行一個時間片後讓出CPU資源,此時同其他線程再次搶佔CPU資源獲得執行權。

2.輪循式;

每個線程執行固定的時間片後讓出CPU資源,以此循環執行每個線程執行相同的時間片後讓出CPU資源交給下一個線程執行。

希望對您有所幫助!~

請問java中的多線程是怎麼回事?

以下全為個人理解,一個字一個字寫噠

1.形象的比喻:

任何編程語言中,如JAVA

System.out.println(“第一個線程”);

System.out.println(“第二個線程”);

System.out.println(“第三個線程”);

普通的方法,這3行都是有順序的,從上到下運行。

而如果使用多線程(代碼較多,不貼出來了),那麼以上3行可以同時運行,無須一行一行地排隊運行。

2.官方的概念

在SUN的JAVA Tutorial中,多線程是Concurrency中的Multi-Threading(Thread翻譯過來是線程)。Thread,象Process,但不同於Process(Process為程式,在ctrl+alt+del出來的任務管理器里的程序全屬於Process)。Process費內存,費CPU等資源,而Thread可以說是輕量級的Process。一個Process里至少有一個Thread,可能有多個Thread。

3.實際應用

一個有Client-Server Model(客戶端-伺服器)的程序。伺服器跟一個客戶交流的時候,可能要花很常時間(如用戶登陸,要費時間去查資料庫)。難道讓其它客戶全都去等著?不行。所以為每個客戶準備一個Thread,所有客戶就可以同時跟伺服器交流,互不干擾。

4.難題

Thread有利弊。線程在應用中,會有諸多問題,編程者必須注意。如:Thread Interference (兩個線程互相干預)

Memory Consistency Errors (內存不一致)

Deadlock (死鎖)

Starvation and Livelock (活瑣)

這些都有解決方法,代碼帶多,不貼了,看參考資料吧!

如何用Java編寫多線程

在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面。

對於直接繼承Thread的類來說,代碼大致框架是:

?

123456789101112 class 類名 extends Thread{ 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }

先看一個簡單的例子:

?

12345678910111213141516171819202122232425262728 /** * @author Rollen-Holt 繼承Thread類,直接調用run方法 * */class hello extends Thread { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i 5; i++) { System.out.println(name + “運行 ” + i); } } public static void main(String[] args) { hello h1=new hello(“A”); hello h2=new hello(“B”); h1.run(); h2.run(); } private String name; }

【運行結果】:

A運行 0

A運行 1

A運行 2

A運行 3

A運行 4

B運行 0

B運行 1

B運行 2

B運行 3

B運行 4

我們會發現這些都是順序執行的,說明我們的調用方法不對,應該調用的是start()方法。

當我們把上面的主函數修改為如下所示的時候:

?

123456 public static void main(String[] args) { hello h1=new hello(“A”); hello h2=new hello(“B”); h1.start(); h2.start(); }

然後運行程序,輸出的可能的結果如下:

A運行 0

B運行 0

B運行 1

B運行 2

B運行 3

B運行 4

A運行 1

A運行 2

A運行 3

A運行 4

因為需要用到CPU的資源,所以每次的運行結果基本是都不一樣的,呵呵。

注意:雖然我們在這裡調用的是start()方法,但是實際上調用的還是run()方法的主體。

那麼:為什麼我們不能直接調用run()方法呢?

我的理解是:線程的運行需要本地操作系統的支持。

如果你查看start的源代碼的時候,會發現:

?

1234567891011121314151617 public synchronized void start() { /** * This method is not invoked for the main method thread or “system” * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state “NEW”. */ if (threadStatus != 0 || this != me) throw new IllegalThreadStateException(); group.add(this); start0(); if (stopBeforeStart) { stop0(throwableFromStop); } } private native void start0();

注意我用紅色加粗的那一條語句,說明此處調用的是start0()。並且這個這個方法用了native關鍵字,次關鍵字表示調用本地操作系統的函數。因為多線程的實現需要本地操作系統的支持。

但是start方法重複調用的話,會出現java.lang.IllegalThreadStateException異常。

通過實現Runnable介面:

大致框架是:

?

123456789101112 class 類名 implements Runnable{ 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }

來先看一個小例子吧:

?

123456789101112131415161718192021222324252627282930 /** * @author Rollen-Holt 實現Runnable介面 * */class hello implements Runnable { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i 5; i++) { System.out.println(name + “運行 ” + i); } } public static void main(String[] args) { hello h1=new hello(“線程A”); Thread demo= new Thread(h1); hello h2=new hello(“線程B”); Thread demo1=new Thread(h2); demo.start(); demo1.start(); } private String name; }

【可能的運行結果】:

線程A運行 0

線程B運行 0

線程B運行 1

線程B運行 2

線程B運行 3

線程B運行 4

線程A運行 1

線程A運行 2

線程A運行 3

線程A運行 4

關於選擇繼承Thread還是實現Runnable介面?

其實Thread也是實現Runnable介面的:

?

12345678 class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }

其實Thread中的run方法調用的是Runnable介面的run方法。不知道大家發現沒有,Thread和Runnable都實現了run方法,這種操作模式其實就是代理模式。關於代理模式,我曾經寫過一個小例子呵呵,大家有興趣的話可以看一下:

Thread和Runnable的區別:

如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable介面的話,則很容易的實現資源共享。

?

1234567891011121314151617181920212223 /** * @author Rollen-Holt 繼承Thread類,不能資源共享 * */class hello extends Thread { public void run() { for (int i = 0; i 7; i++) { if (count 0) { System.out.println(“count= ” + count–); } } } public static void main(String[] args) { hello h1 = new hello(); hello h2 = new hello(); hello h3 = new hello(); h1.start(); h2.start(); h3.start(); } private int count = 5; }

【運行結果】:

count= 5

count= 4

count= 3

count= 2

count= 1

count= 5

count= 4

count= 3

count= 2

count= 1

count= 5

count= 4

count= 3

count= 2

count= 1

大家可以想像,如果這個是一個買票系統的話,如果count表示的是車票的數量的話,說明並沒有實現資源的共享。

我們換為Runnable介面:

?

12345678910111213141516171819 /** * @author Rollen-Holt 繼承Thread類,不能資源共享 * */class hello implements Runnable { public void run() { for (int i = 0; i 7; i++) { if (count 0) { System.out.println(“count= ” + count–); } } } public static void main(String[] args) { hello he=new hello(); new Thread(he).start(); } private int count = 5; }

【運行結果】:

count= 5

count= 4

count= 3

count= 2

count= 1

總結一下吧:

實現Runnable介面比繼承Thread類所具有的優勢:

1):適合多個相同的程序代碼的線程去處理同一個資源

2):可以避免java中的單繼承的限制

3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。

所以,本人建議大家勁量實現介面。

?

java 多線程

所要執行的指令,也包括了執行指令所需的系統資源,不同進程所佔用的系統資源相對獨立。所以進程是重量級的任務,它們之間的通信和轉換都需要操作系統付出較大的開銷。

線程是進程中的一個實體,是被系統獨立調度和分派的基本單位。線程自己基本上不擁有系統資源,但它可以與同屬一個進程的其他線程共享進程所擁有的全部資源。所以線程是輕量級的任務,它們之間的通信和轉換隻需要較小的系統開銷。

Java支持多線程編程,因此用Java編寫的應用程序可以同時執行多個任務。Java的多線程機制使用起來非常方便,用戶只需關注程序細節的實現,而不用擔心後台的多任務系統。

Java語言里,線程表現為線程類。Thread線程類封裝了所有需要的線程操作控制。在設計程序時,必須很清晰地區分開線程對象和運行線程,可以將線程對象看作是運行線程的控制面板。在線程對象里有很多方法來控制一個線程是否運行,睡眠,掛起或停止。線程類是控制線程行為的唯一的手段。一旦一個Java程序啟動後,就已經有一個線程在運行。可通過調用Thread.currentThread方法來查看當前運行的是哪一個線程。

class ThreadTest{

public static void main(String args[]){

Thread t = Thread.currentThread();

t.setName(“單線程”); //對線程取名為”單線程”

t.setPriority(8);

//設置線程優先順序為8,最高為10,最低為1,默認為5

System.out.println(“The running thread: ” + t);

// 顯示線程信息

try{

for(int i=0;i3;i++){

System.out.println(“Sleep time ” + i);

Thread.sleep(100); // 睡眠100毫秒

}

}catch(InterruptedException e){// 捕獲異常

System.out.println(“thread has wrong”);

}

}

}

多線程的實現方法

繼承Thread類

可通過繼承Thread類並重寫其中的run()方法來定義線程體以實現線程的具體行為,然後創建該子類的對象以創建線程。

在繼承Thread類的子類ThreadSubclassName中重寫run()方法來定義線程體的一般格式為:

public class ThreadSubclassName extends Thread{

public ThreadSubclassName(){

….. // 編寫子類的構造方法,可預設

}

public void run(){

….. // 編寫自己的線程代碼

}

}

用定義的線程子類ThreadSubclassName創建線程對象的一般格式為:

ThreadSubclassName ThreadObject =

new ThreadSubclassName();

然後,就可啟動該線程對象表示的線程:

ThreadObject.start(); //啟動線程

應用繼承類Thread的方法實現多線程的程序。本程序創建了三個單獨的線程,它們分別列印自己的「Hello World!」。

class ThreadDemo extends Thread{

private String whoami;

private int delay;

public ThreadDemo(String s,int d){

whoami=s;

delay=d;

}

public void run(){

try{

sleep(delay);

}catch(InterruptedException e)

System.out.println(“Hello World!” + whoami

+ ” ” + delay);

}

}

public class MultiThread{

public static void main(String args[]){

ThreadDemo t1,t2,t3;

t1 = new ThreadDemo(“Thread1”,

(int)(Math.random()*2000));

t2 = new ThreadDemo(“Thread2”,

(int)(Math.random()*2000));

t3 = new ThreadDemo(“Thread3”,

(int)(Math.random()*2000));

t1.start();

t2.start();

t3.start();

}

}

實現Runnable介面

編寫多線程程序的另一種的方法是實現Runnable介面。在一個類中實現Runnable介面(以後稱實現Runnable介面的類為Runnable類),並在該類中定義run()方法,然後用帶有Runnable參數的Thread類構造方法創建線程。

創建線程對象可用下面的兩個步驟來完成:

(1)生成Runnable類ClassName的對象

ClassName RunnableObject = new ClassName();

(2)用帶有Runnable參數的Thread類構造方法創建線程對象。新創建的線程的指針將指向Runnable類的實例。用該Runnable類的實例為線程提供 run()方法—線程體。

Thread ThreadObject = new Thread(RunnableObject);

然後,就可啟動線程對象ThreadObject表示的線程:

ThreadObject.start();

在Thread類中帶有Runnable介面的構造方法有:

public Thread(Runnable target);

public Thread(Runnable target, String name);

public Thread(String name);

public Thread(ThreadGroup group,Runnable target);

public Thread(ThreadGroup group,Runnable target,

String name);

其中,參數Runnable target表示該線程執行時運行target的run()方法,String name以指定名字構造線程,ThreadGroup group表示創建線程組。

用Runnable介面實現的多線程。

class TwoThread implements Runnable{

TwoThread(){

Thread t1 = Thread.currentThread();

t1.setName(“第一主線程”);

System.out.println(“正在運行的線程: ” + t1);

Thread t2 = new Thread(this,”第二線程”);

System.out.println(“創建第二線程”);

t2.start();

try{

System.out.println(“第一線程休眠”);

Thread.sleep(3000);

}catch(InterruptedException e){

System.out.println(“第一線程有錯”);

}

System.out.println(“第一線程退出”);

}

public void run(){

try{

for(int i = 0;i 5;i++){

System.out.println(「第二線程的休眠時間:」

+ i);

Thread.sleep(1000);

}

}catch(InterruptedException e){

System.out.println(“線程有錯”);

}

System.out.println(“第二線程退出”);

}

public static void main(String args[]){

new TwoThread();

}

}

程序運行結果如下:

正在運行的線程: Thread[第一主線程,5,main

創建第二線程

第一線程休眠

第二線程的休眠時間:0

第二線程的休眠時間:1

第二線程的休眠時間:2

第一線程退出

第二線程的休眠時間:3

第二線程的休眠時間:4

第二線程退出

另外,虛機團上產品團購,超級便宜

java 多線程是什麼?

線程定義比較抽象,簡單的說就是一個代碼執行流。許多執行流可以混合在一起由CPU調度。線程是允許各種任務交互執行的方式。

Java的線程在操作系統的實現模式依系統不同而不同,可能是系統級別的進程或線程,但對於程序員來說並沒有影響。

任務交互的一個好處是增加程序響應。如一個界面程序執行一段耗時的資料庫查詢,使用單獨的線程可以讓界面依然響應用戶的其他輸入,而單線程只能等待查詢結束再處理。

JVM以及操作系統會優先處理優先順序別高的線程,但不代表這些線程一定會先完成。設定優先順序只能建議系統更快的處理,而不能強制。

另外,在運行時,並沒有按照函數分界,而是按照機器碼/彙編碼分界。也就是說不保證任何一段代碼是被完整而不打斷的執行的(除非你已經使用同步手段)。正由於如此,各種線程同步的方法應運而生。

原創文章,作者:CAATE,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/130124.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
CAATE的頭像CAATE
上一篇 2024-10-03 23:27
下一篇 2024-10-03 23:27

相關推薦

  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Bean載入過程

    Java Bean載入過程涉及到類載入器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean載入的過程。 一、類載入器 類載入器是Java虛擬機…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • Python簡單數學計算

    本文將從多個方面介紹Python的簡單數學計算,包括基礎運算符、函數、庫以及實際應用場景。 一、基礎運算符 Python提供了基礎的算術運算符,包括加(+)、減(-)、乘(*)、除…

    編程 2025-04-29
  • Python滿天星代碼:讓編程變得更加簡單

    本文將從多個方面詳細闡述Python滿天星代碼,為大家介紹它的優點以及如何在編程中使用。無論是剛剛接觸編程還是資深程序員,都能從中獲得一定的收穫。 一、簡介 Python滿天星代碼…

    編程 2025-04-29
  • VSCode為什麼無法運行Java

    解答:VSCode無法運行Java是因為默認情況下,VSCode並沒有集成Java運行環境,需要手動添加Java運行環境或安裝相關插件才能實現Java代碼的編寫、調試和運行。 一、…

    編程 2025-04-29

發表回復

登錄後才能評論