java線程速覽(java進程線程)

本文目錄一覽:

java有幾種實現線程的方式

java創建線程的方式有三種

第一種是繼承Thread類 實現方法run() 不可以拋異常 無返回值

第二種是實現Runnable介面 實現方法run() 不可以拋異常 無返回值

第三種是實現CallableT介面,介面中要覆蓋的方法是 public T call() 注意:此方法可以拋異常,而前兩種不能 而且此方法可以有返回值

第三種如何運行呢 Callable介面在util.concurrent包中,由線程池提交

import java.util.concurrent.*;

ExecutorService e = Executors.newFixedThreadPool(10); 參數表示最多可以運行幾個線程

e.submit(); 這個裡面參數傳 實現Callable介面那個類的對象

在Java 中多線程的實現方法有哪些,如何使用

Java多線程的創建及啟動

Java中線程的創建常見有如三種基本形式

1.繼承Thread類,重寫該類的run()方法。

複製代碼

1 class MyThread extends Thread {

2  

3     private int i = 0;

4

5     @Override

6     public void run() {

7         for (i = 0; i 100; i++) {

8             System.out.println(Thread.currentThread().getName() + ” ” + i);

9         }

10     }

11 }

複製代碼

複製代碼

1 public class ThreadTest {

2

3     public static void main(String[] args) {

4         for (int i = 0; i 100; i++) {

5             System.out.println(Thread.currentThread().getName() + ” ” + i);

6             if (i == 30) {

7                 Thread myThread1 = new MyThread();     // 創建一個新的線程  myThread1  此線程進入新建狀態

8                 Thread myThread2 = new MyThread();     // 創建一個新的線程 myThread2 此線程進入新建狀態

9                 myThread1.start();                     // 調用start()方法使得線程進入就緒狀態

10                 myThread2.start();                     // 調用start()方法使得線程進入就緒狀態

11             }

12         }

13     }

14 }

複製代碼

如上所示,繼承Thread類,通過重寫run()方法定義了一個新的線程類MyThread,其中run()方法的方法體代表了線程需要完成的任務,稱之為線程執行體。當創建此線程類對象時一個新的線程得以創建,並進入到線程新建狀態。通過調用線程對象引用的start()方法,使得該線程進入到就緒狀態,此時此線程並不一定會馬上得以執行,這取決於CPU調度時機。

2.實現Runnable介面,並重寫該介面的run()方法,該run()方法同樣是線程執行體,創建Runnable實現類的實例,並以此實例作為Thread類的target來創建Thread對象,該Thread對象才是真正的線程對象。

複製代碼

1 class MyRunnable implements Runnable {

2     private int i = 0;

3

4     @Override

5     public void run() {

6         for (i = 0; i 100; i++) {

7             System.out.println(Thread.currentThread().getName() + ” ” + i);

8         }

9     }

10 }

複製代碼

複製代碼

1 public class ThreadTest {

2

3     public static void main(String[] args) {

4         for (int i = 0; i 100; i++) {

5             System.out.println(Thread.currentThread().getName() + ” ” + i);

6             if (i == 30) {

7                 Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象

8                 Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創建新的線程

9                 Thread thread2 = new Thread(myRunnable);

10                 thread1.start(); // 調用start()方法使得線程進入就緒狀態

11                 thread2.start();

12             }

13         }

14     }

15 }

複製代碼

相信以上兩種創建新線程的方式大家都很熟悉了,那麼Thread和Runnable之間到底是什麼關係呢?我們首先來看一下下面這個例子。

複製代碼

1 public class ThreadTest {

2

3     public static void main(String[] args) {

4         for (int i = 0; i 100; i++) {

5             System.out.println(Thread.currentThread().getName() + ” ” + i);

6             if (i == 30) {

7                 Runnable myRunnable = new MyRunnable();

8                 Thread thread = new MyThread(myRunnable);

9                 thread.start();

10             }

11         }

12     }

13 }

14

15 class MyRunnable implements Runnable {

16     private int i = 0;

17

18     @Override

19     public void run() {

20         System.out.println(“in MyRunnable run”);

21         for (i = 0; i 100; i++) {

22             System.out.println(Thread.currentThread().getName() + ” ” + i);

23         }

24     }

25 }

26

27 class MyThread extends Thread {

28

29     private int i = 0;

30  

31     public MyThread(Runnable runnable){

32         super(runnable);

33     }

34

35     @Override

36     public void run() {

37         System.out.println(“in MyThread run”);

38         for (i = 0; i 100; i++) {

39             System.out.println(Thread.currentThread().getName() + ” ” + i);

40         }

41     }

42 }

複製代碼

同樣的,與實現Runnable介面創建線程方式相似,不同的地方在於

1 Thread thread = new MyThread(myRunnable);

那麼這種方式可以順利創建出一個新的線程么?答案是肯定的。至於此時的線程執行體到底是MyRunnable介面中的run()方法還是MyThread類中的run()方法呢?通過輸出我們知道線程執行體是MyThread類中的run()方法。其實原因很簡單,因為Thread類本身也是實現了Runnable介面,而run()方法最先是在Runnable介面中定義的方法。

1 public interface Runnable {

2  

3     public abstract void run();

4  

5 }

我們看一下Thread類中對Runnable介面中run()方法的實現:

複製代碼

@Override

public void run() {

if (target != null) {

target.run();

}

}

複製代碼

也就是說,當執行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執行target中的run()方法,也就是實現了Runnable介面並重寫了run()方法的類中的run()方法。但是上述給到的列子中,由於多態的存在,根本就沒有執行到Thread類中的run()方法,而是直接先執行了運行時類型即MyThread類中的run()方法。

3.使用Callable和Future介面創建線程。具體是創建Callable介面的實現類,並實現clall()方法。並使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象作為Thread對象的target來創建線程。

看著好像有點複雜,直接來看一個例子就清晰了。

複製代碼

1 public class ThreadTest {

2

3     public static void main(String[] args) {

4

5         CallableInteger myCallable = new MyCallable();    // 創建MyCallable對象

6         FutureTaskInteger ft = new FutureTaskInteger(myCallable); //使用FutureTask來包裝MyCallable對象

7

8         for (int i = 0; i 100; i++) {

9             System.out.println(Thread.currentThread().getName() + ” ” + i);

10             if (i == 30) {

11                 Thread thread = new Thread(ft);   //FutureTask對象作為Thread對象的target創建新的線程

12                 thread.start();                      //線程進入到就緒狀態

13             }

14         }

15

16         System.out.println(“主線程for循環執行完畢..”);

17      

18         try {

19             int sum = ft.get();            //取得新創建的新線程中的call()方法返回的結果

20             System.out.println(“sum = ” + sum);

21         } catch (InterruptedException e) {

22             e.printStackTrace();

23         } catch (ExecutionException e) {

24             e.printStackTrace();

25         }

26

27     }

28 }

29

30

31 class MyCallable implements CallableInteger {

32     private int i = 0;

33

34     // 與run()方法不同的是,call()方法具有返回值

35     @Override

36     public Integer call() {

37         int sum = 0;

38         for (; i 100; i++) {

39             System.out.println(Thread.currentThread().getName() + ” ” + i);

40             sum += i;

41         }

42         return sum;

43     }

44

45 }

複製代碼

首先,我們發現,在實現Callable介面中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執行體,同時還具有返回值!在創建新的線程時,是通過FutureTask來包裝MyCallable對象,同時作為了Thread對象的target。那麼看下FutureTask類的定義:

1 public class FutureTaskV implements RunnableFutureV {

2  

3     //….

4  

5 }

1 public interface RunnableFutureV extends Runnable, FutureV {

2  

3     void run();

4  

5 }

於是,我們發現FutureTask類實際上是同時實現了Runnable和Future介面,由此才使得其具有Future和Runnable雙重特性。通過Runnable特性,可以作為Thread對象的target,而Future特性,使得其可以取得新創建線程中的call()方法的返回值。

執行下此程序,我們發現sum = 4950永遠都是最後輸出的。而「主線程for循環執行完畢..」則很可能是在子線程循環中間輸出。由CPU的線程調度機制,我們知道,「主線程for循環執行完畢..」的輸出時機是沒有任何問題的,那麼為什麼sum =4950會永遠最後輸出呢?

原因在於通過ft.get()方法獲取子線程call()方法的返回值時,當子線程此方法還未執行完畢,ft.get()方法會一直阻塞,直到call()方法執行完畢才能取到返回值。

上述主要講解了三種常見的線程創建方式,對於線程的啟動而言,都是調用線程對象的start()方法,需要特別注意的是:不能對同一線程對象兩次調用start()方法。

你好,本題已解答,如果滿意

請點右下角「採納答案」。

【Java基礎】線程生命周期有哪些階段?

Java線程具有五中基本狀態

新建狀態(New):當線程對象對創建後,即進入了新建狀態,如:Thread t = new MyThread();

就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處於就緒狀態的線程,只是說明此線程已經做好了準備,隨時等待CPU調度執行,並不是說執行了t.start()此線程立即就會執行;

運行狀態(Running):當CPU開始調度處於就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。註:就 緒狀態是進入到運行狀態的唯一入口,也就是說,線程要想進入運行狀態執行,首先必須處於就緒狀態中;

阻塞狀態(Blocked):處於運行狀態中的線程由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:

1.等待阻塞:運行狀態中的線程執行wait()方法,使本線程進入到等待阻塞狀態;

2.同步阻塞 — 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所佔用),它會進入同步阻塞狀態;

3.其他阻塞 — 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。

死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

什麼是Java多線程

多線程的概念?

說起多線程,那麼就不得不說什麼是線程,而說起線程,又不得不說什麼是進程。

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

進程可以簡單的理解為一個可以獨立運行的程序單位。它是線程的集合,進程就是有一個或多個線程構成的,每一個線程都是進程中的一條執行路徑。

那麼多線程就很容易理解:多線程就是指一個進程中同時有多個執行路徑(線程)正在執行。

為什麼要使用多線程?

1.在一個程序中,有很多的操作是非常耗時的,如資料庫讀寫操作,IO操作等,如果使用單線程,那麼程序就必須等待這些操作執行完成之後才能執行其他操作。使用多線程,可以在將耗時任務放在後台繼續執行的同時,同時執行其他操作。

2.可以提高程序的效率。

3.在一些等待的任務上,如用戶輸入,文件讀取等,多線程就非常有用了。

缺點:

1.使用太多線程,是很耗系統資源,因為線程需要開闢內存。更多線程需要更多內存。

2.影響系統性能,因為操作系統需要在線程之間來回切換。

3.需要考慮線程操作對程序的影響,如線程掛起,中止等操作對程序的影響。

4.線程使用不當會發生很多問題。

總結:多線程是非同步的,但這不代表多線程真的是幾個線程是在同時進行,實際上是系統不斷地在各個線程之間來回的切換(因為系統切換的速度非常的快,所以給我們在同時運行的錯覺)。

2.多線程與高並發的聯繫。

高並發:高並髮指的是一種系統運行過程中遇到的一種「短時間內遇到大量操作請求」的情況,主要發生在web系統集中大量訪問或者socket埠集中性收到大量請求(例如:12306的搶票情況;天貓雙十一活動)。該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,資料庫的操作等。如果高並發處理不好,不僅僅降低了用戶的體驗度(請求響應時間過長),同時可能導致系統宕機,嚴重的甚至導致OOM異常,系統停止工作等。如果要想系統能夠適應高並髮狀態,則需要從各個方面進行系統優化,包括,硬體、網路、系統架構、開發語言的選取、數據結構的運用、演算法優化、資料庫優化……。

而多線程只是在同/非同步角度上解決高並發問題的其中的一個方法手段,是在同一時刻利用計算機閑置資源的一種方式。

多線程在高並發問題中的作用就是充分利用計算機資源,使計算機的資源在每一時刻都能達到最大的利用率,不至於浪費計算機資源使其閑置。

3.線程的創建,停止,常用方法介紹。

1.線程的創建:

線程創建主要有2種方式,一種是繼承Thread類,重寫run方法即可;(Thread類實現了Runable介面)

另一種則是實現Runable介面,也需要重寫run方法。

線程的啟動,調用start()方法即可。 我們也可以直接使用線程對象的run方法,不過直接使用,run方法就只是一個普通的方法了。

其他的還有: 通過匿名內部類的方法創建;實現Callable介面。。。。。

2.線程常用方法:

currentThread()方法:該方法返回當前線程的信息 .getName()可以返回線程名稱。

isAlive()方法:該方法判斷當前線程是否處於活動狀態。

sleep()方法:該方法是讓「當前正在執行的線程「休眠指定的時間,正在執行的線程是指this.currentThread()返回的線程。

getId()方法:該方法是獲取線程的唯一標識。

3.線程的停止:

在java中,停止線程並不簡單,不想for。。break那樣說停就停,需要一定的技巧。

線程的停止有3種方法:

1.線程正常終止,即run()方法運行結束正常停止。

2.使用interrupt方法中斷線程。

3.使用stop方法暴力停止線程。

interrupt方法中斷線程介紹:

interrupt方法其實並不是直接中斷線程,只是給線程添加一個中斷標誌。

判斷線程是否是停止狀態:

this.interrupted(); 判斷當前線程是否已經中斷。(判斷的是這個方法所在的代碼對應的線程,而不是調用對象對應的線程)

this.isInterrupted(); 判斷線程是否已經中斷。(誰調用,判斷誰)

註:.interrupted()與isInterrupted()的區別:

interrupted()方法判斷的是所在代碼對應的線程是否中斷,而後者判斷的是調用對象對應的線程是否停止

前者執行後有清除狀態的功能(如連續調用兩次時,第一次返回true,則第二次會返回false)

後者沒有清除狀態的功能(兩次返回都為true)

真正停止線程的方法:

異常法:

在run方法中 使用 this.interrupted();判斷線程終止狀態,如果為true則 throw new interruptedException()然後捕獲該異常即可停止線程。

return停止線程:

在run方法中 使用 this.interrupted();判斷線程終止狀態,如果為true則return停止線程。 (建議使用異常法停止線程,因為還可以在catch中使線程向上拋,讓線程停止的事件得以傳播)。

暴力法:

使用stop()方法強行停止線程(強烈不建議使用,會造成很多不可預估的後果,已經被標記為過時)

(使用stop方法會拋出 java.lang.ThreadDeath 異常,並且stop方法會釋放鎖,很容易造成數據不一致)

註:在休眠中停止線程:

在sleep狀態下停止線程 會報異常,並且會清除線程狀態值為false;

先停止後sleep,同樣會報異常 sleep interrupted;

4.守護線程。

希望對您有所幫助!~

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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
簡單一點的頭像簡單一點
上一篇 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 Bean載入過程

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

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

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

    編程 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
  • VSCode為什麼無法運行Java

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

    編程 2025-04-29
  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29
  • Java 8 Group By 會影響排序嗎?

    是的,Java 8中的Group By會對排序產生影響。本文將從多個方面探討Group By對排序的影響。 一、Group By的概述 Group By是SQL中的一種常見操作,它…

    編程 2025-04-29

發表回復

登錄後才能評論