並發性(concurrency)和並行性(parallel)是兩個概念,並行是指在同一時刻,有多條指令在多個處理器上同時執行;並發指在同一時刻只能有一條指令執行,但多個進程指令被快速輪換執行,使得宏觀上具有多個進程同時執行的效果。
多線程編程優點:
- 進程之間不能共享內存,但線程之間共享內存非常容易。
- 系統創建線程所分配的資源相對創建進程而言,代價非常小。
Java中實現線程的方式目前有三種:
一:繼承Thread類創建線程類
package com.clzhang.sample.thread; // 通過繼承Thread類來創建線程類 public class ThreadByExtends extends Thread { private int i; @Override public void run() { // 當線程類繼承Thread類時,直接使用this即可獲取當前線程句柄。 // 因此可以直接調用getName()方法返回當前線程的名稱。 System.out.println("當前線程名稱是:" + getName()); for (; i < 5; i++) { System.out.println(getName() + ":" + i); try { // 保證讓別的線程也有執行的機會 Thread.sleep(10); } catch (InterruptedException e) { } } } public static void main(String[] args) { // 靜態方法沒有this,只能通過Thread.currentThread獲取當前線程句柄 System.out.println(Thread.currentThread().getName()); // 創建、並啟動第一條線程 new ThreadByExtends().start(); // 創建、並啟動第二條線程 new ThreadByExtends().start(); } }
輸出:
main
當前線程名稱是:Thread-0
Thread-0:0
當前線程名稱是:Thread-1
Thread-1:0
Thread-0:1
Thread-1:1
Thread-1:2
Thread-0:2
Thread-1:3
Thread-0:3
Thread-0:4
Thread-1:4
二:實現Runnable接口創建線程類
package com.clzhang.sample.thread; /** * 通過實現Runnable接口來創建線程類 * 1.Runnable非常適合多個相同線程來處理同一份資源的情況 * 2.Runnable可以避免由於Java的單繼承機制帶來的局限 * 3.如果想獲取當前線程句柄,只能用Thread.currentThread()方法 */ public class ThreadByRunnable implements Runnable { private int i; @Override public void run() { System.out.println("當前線程名稱是:" + Thread.currentThread().getName()); for (; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); try { // 因為sleep是靜態方法,所以不需要通過Thread.currentThread()方法獲取當前線程句柄 Thread.sleep(10); } catch (InterruptedException e) { } } } public static void main(String[] args) { ThreadByRunnable st = new ThreadByRunnable(); new Thread(st, "新線程1").start(); new Thread(st, "新線程2").start(); } }
輸出:
當前線程名稱是:新線程1
當前線程名稱是:新線程2
新線程2:0
新線程1:0
新線程2:2
新線程1:2
新線程2:3
新線程1:4
三:使用Calable和Future創建具備返回值的線程
package com.clzhang.sample.thread; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; // 實現Callable接口來實現線程 public class ThreadByCallable implements Callable<Integer> { @Override public Integer call() { System.out.println("當前線程名稱是:" + Thread.currentThread().getName()); int i = 0; for (; i < 5; i++) { System.out.println("循環變量i的值:" + i); } // call()方法有返回值 return i; } public static void main(String[] args) { ThreadByCallable rt = new ThreadByCallable(); // 使用FutureTask來包裝Callable對象 FutureTask<Integer> task = new FutureTask<Integer>(rt); new Thread(task, "有返回值的線程").start(); try { // 獲取線程返回值 System.out.println("子線程的返回值:" + task.get()); } catch (Exception ex) { ex.printStackTrace(); } } }
輸出:
當前線程名稱是:有返回值的線程
循環變量i的值:0
循環變量i的值:1
循環變量i的值:2
循環變量i的值:3
循環變量i的值:4
子線程的返回值:5
總結
用Runnable與Callable接口的方式創建多線程的特點:
- 線程類只是實現了Runnable接口或Callable接口,還可以繼承其它類。
- 在這種方式下,多個線程可以共享一個target對象,所以非常適合多個線程來處理同一份資源情況。
- 如果需要訪問當前線程,需要使用Thread.currentThread方法。
- Callable接口與Runnable接口相比,只是Callable接口可以返回值而已。
用Thread類的方式創建多線程的特點:
- 因為線程已經繼承Thread類,所以不可以再繼承其它類。
- 如果需要訪問當前線程,直接使用this即可。