搜尋
首頁Javajava教程Java實作多執行緒的方法有哪些

前言

Java多執行緒實作方式主要有四種:

① 繼承Thread類別、實作Runnable介面

② 實作Callable介面透過FutureTask包裝器來創建Thread執行緒​​

③ 使用ExecutorService、Callable

④ Future實作有傳回結果的多執行緒

其中前兩種方式執行緒執行完後都沒有回傳值,後兩種是帶返回值的。

一、四種方式實作多執行緒

1.繼承Thread類別建立執行緒

Thread類別本質上是實作了Runnable介面的實例,表示一個執行緒的實例。使用Thread類別的start()實例方法是啟動執行緒的唯一途徑。執行run()方法的新執行緒是透過呼叫start()方法來啟動的,而start()方法是一個原生方法。這種方式實作多執行緒很簡單,透過自己的類別直接extend Thread,並複寫run()方法,就可以啟動新執行緒並執行自己定義的run()方法。例如:

public class MyThread extends Thread {  
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}  
MyThread myThread1 = new MyThread();  
MyThread myThread2 = new MyThread();  
myThread1.start();  
myThread2.start();

2.實作Runnable介面建立執行緒

如果自己的類別已經extends另一個類,就無法直接extends Thread,此時,可以實作一個Runnable接口,如下:

public class MyThread extends OtherClass implements Runnable {  
  public void run() {  
   System.out.println("MyThread.run()");  
  }  
}

為了啟動MyThread,需要先實例化一個Thread,並傳入自己的MyThread實例:

MyThread myThread = new MyThread();  
Thread thread = new Thread(myThread);  
thread.start();

事實上,當傳入一個Runnable target參數給Thread後,Thread的run( )方法就會呼叫target.run(),參考JDK原始碼:

public void run() {  
  if (target != null) {  
   target.run();  
  }  
}

3.實作Callable介面

透過FutureTask包裝器來建立Thread執行緒​​

#Callable介面(也只有一個方法)定義如下:

public interface Callable<V>   { 
  V call() throws Exception;   } 
public class SomeCallable<V> extends OtherClass implements Callable<V> {
    @Override
    public V call() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }
}
Callable<V> oneCallable = new SomeCallable<V>();   
//由Callable<Integer>创建一个FutureTask<Integer>对象:   
FutureTask<V> oneTask = new FutureTask<V>(oneCallable);   
//注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。 
  //由FutureTask<Integer>创建一个Thread对象:   
Thread oneThread = new Thread(oneTask);   
oneThread.start();   //至此,一个线程就创建完成了。

4.實作有回傳結果的執行緒

使用ExecutorService、Callable、Future實作有傳回結果的執行緒

#ExecutorService、 Callable、Future三個介面其實都是屬於Executor框架。在JDK1.5中,引入了傳回結果的執行緒作為新特性,不再需要費盡周折來取得回傳值。而且自己實現了也可能漏洞百出。

可傳回值的任務必須實作Callable介面。類似的,無回傳值的任務必須實作Runnable介面。

執行Callable任務後,可以取得一個Future的對象,在該對像上呼叫get就可以取得到Callable任務返回的Object了。

注意:get方法是阻塞的,也就是:執行緒無回傳結果,get方法會一直等待。

再結合線程池介面ExecutorService就可以實現傳說中有回傳結果的多線程了。

在JDK1.5下進行了驗證並且沒有問題,可以直接使用下面提供的有返回結果的多線程測試範例。程式碼如下:

import java.util.concurrent.*;  
import java.util.Date;  
import java.util.List;  
import java.util.ArrayList;  
/** 
* 有返回值的线程 
*/  
@SuppressWarnings("unchecked")  
public class Test {  
public static void main(String[] args) throws ExecutionException,  
    InterruptedException {  
   System.out.println("----程序开始运行----");  
   Date date1 = new Date();  
   int taskSize = 5;  
   // 创建一个线程池  
   ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
   // 创建多个有返回值的任务  
   List<Future> list = new ArrayList<Future>();  
   for (int i = 0; i < taskSize; i++) {  
    Callable c = new MyCallable(i + " ");  
    // 执行任务并获取Future对象  
    Future f = pool.submit(c);  
    // System.out.println(">>>" + f.get().toString());  
    list.add(f);  
   }  
   // 关闭线程池  
   pool.shutdown();  
   // 获取所有并发任务的运行结果  
   for (Future f : list) {  
    // 从Future对象上获取任务的返回值,并输出到控制台  
    System.out.println(">>>" + f.get().toString());  
   }  
   Date date2 = new Date();  
   System.out.println("----程序结束运行----,程序运行时间【"  
     + (date2.getTime() - date1.getTime()) + "毫秒】");  
}  
}  
class MyCallable implements Callable<Object> {  
private String taskNum;  
MyCallable(String taskNum) {  
   this.taskNum = taskNum;  
}  
public Object call() throws Exception {  
   System.out.println(">>>" + taskNum + "任务启动");  
   Date dateTmp1 = new Date();  
   Thread.sleep(1000);  
   Date dateTmp2 = new Date();  
   long time = dateTmp2.getTime() - dateTmp1.getTime();  
   System.out.println(">>>" + taskNum + "任务终止");  
   return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";  
}  
}

二、多執行緒相關知識

1.Runnable 和Callable 的差異

主要差異Runnable 介面run 方法無回傳值;

Callable 介面call 方法有回傳值,支援泛型Runnable 介面run 方法只能拋出執行時期異常,且無法擷取處理;

Callable 介面call 方法允許拋出異常,可以取得例外資訊

2.如何啟動一個新執行緒、呼叫start 和run 方法的差異

執行緒物件呼叫run 方法不開啟執行緒。僅是對象呼叫方法。

線程物件呼叫start 開啟線程,並讓jvm 呼叫run 方法在開啟的線程中執行呼叫start 方法可以啟動線程,並且使得線程進入就緒狀態,而run 方法只是thread 的一個普通方法,還是在主線程中執行。

3.線程相關的基本方法

線程相關的基本方法有wait,notify,notifyAll,sleep,join,yield 等

線程等待(wait) 呼叫該方法的執行緒進入waiting狀態,只有等待另外執行緒的通知或被中斷才會傳回,需要注意的是呼叫wait()方法後,會釋放物件的鎖。因此,wait 方 法一般用在同步方法或同步程式碼區塊中。

執行緒睡眠(sleep) sleep 導致目前執行緒休眠,與wait 方法不同的是sleep 不會釋放目前佔有的鎖定,sleep(long)會導致執行緒進入TIMED-WATING 狀態,而wait()方法會導致目前執行緒進入WATING 狀態.

執行緒讓步(yield) yield 會使目前執行緒讓出CPU 執行時間片,並與其他執行緒一起重新競爭CPU 時間片。一般情況下,優先順序高的執行緒有較大的可能性成功競爭得到 CPU 時間片,但這又不是絕對的,有的作業系統對 執行緒優先權並不敏感。

線程中斷(interrupt) 中斷一個線程,其本意是給這個線程一個通知信號,會影響這個線程內部的 一個中斷標識位。這個執行緒本身並不會因此而改變狀態(如阻塞,終止等)

Join 等待其他執行緒終止join() 方法,等待其他執行緒終止,在目前執行緒中呼叫一個執行緒的join() 方法,則當前執行緒轉為阻塞狀態,回到另一個執行緒結束,當前執行緒再由阻塞狀態變為就緒狀態,等待cpu 的寵幸.

 線程喚醒(notify) Object 類別中的notify() 方法,喚醒在此物件監視器上等待的單一線程,如果所有線程都在此物件上等待,則會選擇喚醒其中一個線程,選擇是任意的,並在對實現做出決定時發生,線程通過調用其中一個wait() 方法,在對象的監視器上等待,直到當前的線程放棄此對像上的鎖定,才能繼續執行被喚醒的線程, 被喚醒的執行緒將以常規方式與在該物件上主動同步的其他所有執行緒進行競爭。另一個類似的方法是 notifyAll(),它可以喚醒在同一監視器上等待的所有執行緒。

4.wait()和sleep()的區別

 ① 來自不同的類別wait(): 來自Object 類別;sleep():來自Thread 類別;

② 關於鎖的釋放: wait(): 在等待的過程中會釋放鎖; sleep():在等待的過程中不會釋放鎖

 ③ 使用的範圍: wait(): 必須在同步程式碼區塊中使用;sleep(): 可以在任何地方使用;

 ④ 是否需要捕獲異常wait():不需要捕獲異常;sleep():需要捕獲異常;

5 .多執行緒原理

多執行緒原理:多執行緒是透過並發的方式進行。對於一個CPU它在某個時間點上,只能執行一個程序,即同一時間只能運行一個進程,CPU會不斷地在這些進程之間切換,每個執行緒執行一個時間。因為CPU的執行速度相對我們的感覺實在太快了,雖然CPU在多個進程之間輪換執行,但我們自己感覺好像多個進程在同時執行。

CPU會在多個進程之間做著切換,如果我們開啟的程式過多,CPU切換到每一個進程的時間也會變長,我們也會感覺機器運作變慢。雖然合理地使用多執行緒可以提高效率,但是過度使用並不能帶來效率上的提升。

多執行緒技術主要解決處理器單元內多個執行緒執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。

Java實作多執行緒的方法有哪些

以上是Java實作多執行緒的方法有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
带你搞懂Java结构化数据处理开源库SPL带你搞懂Java结构化数据处理开源库SPLMay 24, 2022 pm 01:34 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于结构化数据处理开源库SPL的相关问题,下面就一起来看一下java下理想的结构化数据处理类库,希望对大家有帮助。

Java集合框架之PriorityQueue优先级队列Java集合框架之PriorityQueue优先级队列Jun 09, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于PriorityQueue优先级队列的相关知识,Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,下面一起来看一下,希望对大家有帮助。

完全掌握Java锁(图文解析)完全掌握Java锁(图文解析)Jun 14, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于java锁的相关问题,包括了独占锁、悲观锁、乐观锁、共享锁等等内容,下面一起来看一下,希望对大家有帮助。

一起聊聊Java多线程之线程安全问题一起聊聊Java多线程之线程安全问题Apr 21, 2022 pm 06:17 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于多线程的相关问题,包括了线程安装、线程加锁与线程不安全的原因、线程安全的标准类等等内容,希望对大家有帮助。

Java基础归纳之枚举Java基础归纳之枚举May 26, 2022 am 11:50 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于枚举的相关问题,包括了枚举的基本操作、集合类对枚举的支持等等内容,下面一起来看一下,希望对大家有帮助。

详细解析Java的this和super关键字详细解析Java的this和super关键字Apr 30, 2022 am 09:00 AM

本篇文章给大家带来了关于Java的相关知识,其中主要介绍了关于关键字中this和super的相关问题,以及他们的一些区别,下面一起来看一下,希望对大家有帮助。

Java数据结构之AVL树详解Java数据结构之AVL树详解Jun 01, 2022 am 11:39 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于平衡二叉树(AVL树)的相关知识,AVL树本质上是带了平衡功能的二叉查找树,下面一起来看一下,希望对大家有帮助。

一文掌握Java8新特性Stream流的概念和使用一文掌握Java8新特性Stream流的概念和使用Jun 23, 2022 pm 12:03 PM

本篇文章给大家带来了关于Java的相关知识,其中主要整理了Stream流的概念和使用的相关问题,包括了Stream流的概念、Stream流的获取、Stream流的常用方法等等内容,下面一起来看一下,希望对大家有帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版