Java 实现多线程的四种方式
在 Java 中實現多線程一共有四種方式:
下面我將對這四種方式進行入門級的解析和演示。
一、繼承 Thread 類
通過繼承 Thread 類實現多線程的步驟如下:
代碼示例如下:
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("我是通過繼承 Thread 類創建的多線程,我叫" + Thread.currentThread().getName());} }class TestMyThread {public static void main(String[] args) {MyThread myThread1 = new MyThread();myThread1.setName("Thread-1");MyThread myThread2 = new MyThread();myThread2.setName("Thread-2");MyThread myThread3 = new MyThread();myThread3.setName("Thread-3");myThread1.start();myThread2.start();myThread3.start();} }為了演示線程執行順序的隨機性,我特意創建了三個線程,并為每一個線程命名,下面是我運行五次程序的執行結果:
// 第一次 我是通過繼承 Thread 類創建的多線程,我叫Thread-2 我是通過繼承 Thread 類創建的多線程,我叫Thread-1 我是通過繼承 Thread 類創建的多線程,我叫Thread-3// 第二次 我是通過繼承 Thread 類創建的多線程,我叫Thread-1 我是通過繼承 Thread 類創建的多線程,我叫Thread-3 我是通過繼承 Thread 類創建的多線程,我叫Thread-2// 第三次 我是通過繼承 Thread 類創建的多線程,我叫Thread-1 我是通過繼承 Thread 類創建的多線程,我叫Thread-3 我是通過繼承 Thread 類創建的多線程,我叫Thread-2// 第四次 我是通過繼承 Thread 類創建的多線程,我叫Thread-1 我是通過繼承 Thread 類創建的多線程,我叫Thread-2 我是通過繼承 Thread 類創建的多線程,我叫Thread-3// 第五次 我是通過繼承 Thread 類創建的多線程,我叫Thread-2 我是通過繼承 Thread 類創建的多線程,我叫Thread-1 我是通過繼承 Thread 類創建的多線程,我叫Thread-3從上面的執行結果我們可以看到線程的執行順序和代碼中編寫的順序沒有關系,線程的執行順序是具有隨機性的。
二、實現 Runnable 接口
Runnable 接口只有一個 run() 方法,源碼如下:
public interface Runnable {public abstract void run(); }通過實現 Runnable 接口實現多線程的步驟如下:
代碼示例如下:
public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("我是通過實現 Runnable 接口創建的多線程,我叫" + Thread.currentThread().getName());} }class TestMyRunnable {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();} }執行結果如下:
我是通過實現 Runnable 接口創建的多線程,我叫Thread-0相比于繼承 Thread 類的方法來說,實現 Runnable 接口是一個更好地選擇,因為 Java 不支持多繼承,但是可以實現多個接口。
有一點值得注意的是 Thread 類也實現了 Runnable 接口,這意味著構造函數 Thread(Runnable target) 不僅可以傳入 Runnable 接口的對象,而且可以傳入一個 Thread 類的對象,這樣就可以將一個 Thread 對象中的 run() 方法交由其他線程進行調用。
三、實現 Callable 接口
Callable 接口只有一個 call() 方法,源碼如下:
public interface Callable<V> {V call() throws Exception; }從源碼我們可以看到 Callable 接口和 Runnable 接口類似,它們之間的區別在于 run() 方法沒有返回值,而 call() 方法是有返回值的。
通過實現 Callable 接口實現多線程的步驟如下:
代碼示例如下:
public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int a = 6;int b = 9;System.out.println("我是通過實現 Callable 接口創建的多線程,我叫" + Thread.currentThread().getName());return a + b;} }class TestMyCallable {public static void main(String[] args) throws ExecutionException, InterruptedException {MyCallable myCallable = new MyCallable();FutureTask<Integer> futureTask = new FutureTask(myCallable);Thread thread = new Thread(futureTask);thread.start();System.out.println("返回值為:" + futureTask.get());} }執行結果如下:
我是通過實現 Callable 接口創建的多線程,我叫Thread-0 返回值為:15FutureTask 類提供了一個 get() 方法用來獲取 call() 方法的返回值,但需要注意的是調用這個方法會導致程序阻塞,必須要等到線程結束后才會得到返回值。
四、線程池
在 Java 中構建一個新的線程是需要一定的系統開銷的,前面三種實現多線程的方法在線程執行完任務后就會將線程銷毀,那么是否可以在線程執行完任務后將線程保存下來,給下一個任務使用呢?答案是可以的,為了解決這個問題,線程池應運而生。
顧名思義,線程池就是用來存儲線程的池子。線程池中包含許多準備運行的線程,我們只需要為線程池提供一個個任務,線程池就會按照一定的規則去調用這些任務,當一個任務完成后,調用這個任務的線程不會死亡,而是留在線程池中準備為下一個任務提供服務。
Executors 類提供了許多靜態工廠方法用來構造線程池,這里我介紹其中的三種:
newFixedThreadPool(int nThreads)
該方法用來構造一個固定大小的線程池,空閑的線程會一直保留著,如果提交的任務數多于空閑線程數,就會把未得到服務的任務放到隊列中等待。
代碼示例如下:
public class MyFixedThreadPool {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executorService = Executors.newFixedThreadPool(3);// 調用 Runnable 任務TestRunnable1 testRunnable1 = new TestRunnable1();for (int i = 0; i < 5; i++) {// 調用 Runnable 任務可以用以下兩種方法,二者的區別在于前者沒返回值,后者有返回值executorService.execute(testRunnable1);Future<?> submit = executorService.submit(testRunnable1);}// 調用 Callable 任務TestCallable1 testCallable1 = new TestCallable1();for (int i = 0; i < 5; i++) {// 調用 Callable 任務只能用這一種方法Future<Integer> submit = executorService.submit(testCallable1);System.out.println("返回值:" + submit.get());}} }class TestRunnable1 implements Runnable {@Overridepublic void run() {System.out.println("我是 Runnable 任務,調用我的線程是:" + Thread.currentThread().getName());} }class TestCallable1 implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("我是 Callable 任務,調用我的線程是:" + Thread.currentThread().getName());return 666;} }newCachedThreadPool()
該方法構建的線程池會立即執行任務,如果當前存在空閑線程,則直接執行任務;如果當前不存在空閑線程,則創建一個新線程執行任務。在該線程池內的空閑線程只會保留 60 秒。
public class MyCachedThreadPool {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executorService = Executors.newCachedThreadPool();// 調用 Runnable 任務TestRunnable2 testRunnable2 = new TestRunnable2();for (int i = 0; i < 5; i++) {// 調用 Runnable 任務可以用以下兩種方法,二者的區別在于前者沒返回值,后者有返回值executorService.execute(testRunnable2);Future<?> submit = executorService.submit(testRunnable2);}// 調用 Callable 任務TestCallable2 testCallable2 = new TestCallable2();for (int i = 0; i < 5; i++) {// 調用 Callable 任務只能用這一種方法Future<Integer> submit = executorService.submit(testCallable2);System.out.println("返回值:" + submit.get());}} }class TestRunnable2 implements Runnable {@Overridepublic void run() {System.out.println("我是 Runnable 任務,調用我的線程是:" + Thread.currentThread().getName());} }class TestCallable2 implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("我是 Callable 任務,調用我的線程是:" + Thread.currentThread().getName());return 666;} }newSingleThreadExecutor()
該方法構建的線程池只存在一個線程,會順序地執行所提交的任務。
public class MySingleThreadExecutor {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executorService = Executors.newSingleThreadExecutor();// 調用 Runnable 任務TestRunnable3 testRunnable3 = new TestRunnable3();for (int i = 0; i < 5; i++) {// 調用 Runnable 任務可以用以下兩種方法,二者的區別在于前者沒返回值,后者有返回值executorService.execute(testRunnable3);Future<?> submit = executorService.submit(testRunnable3);}// 調用 Callable 任務TestCallable3 testCallable3 = new TestCallable3();for (int i = 0; i < 5; i++) {// 調用 Callable 任務只能用這一種方法Future<Integer> submit = executorService.submit(testCallable3);System.out.println("返回值:" + submit.get());}} }class TestRunnable3 implements Runnable {@Overridepublic void run() {System.out.println("我是 Runnable 任務,調用我的線程是:" + Thread.currentThread().getName());} }class TestCallable3 implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("我是 Callable 任務,調用我的線程是:" + Thread.currentThread().getName());return 666;} }總結
以上是生活随笔為你收集整理的Java 实现多线程的四种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: h5 android底部导航栏,安卓 微
- 下一篇: AI编程软件会取代程序员吗?