public static void main(String[] args){ add(); remove(); get(); System.out.println(222); } public static void add(){ // 一萬次循環 } public static void remove(){ } public static void get(){ }
大部分操做系統都支持多進程併發運行,如今的操做系統幾乎都支持同時運行多個程序。好比:如今咱們上課一邊使用編輯器,一邊使用錄屏軟件,同時還開着畫圖板, dos窗口等軟件。此時,這些程序是在同時運行,」感受這些軟件好像在同一時刻運行着「。
實際上,CPU(中央處理器)使用搶佔式調度模式在多個線程間進行着高速的切換。對於CPU的一個核而言,某個時刻,只能執行一個線程,而 CPU的在多個線程間切換速度相對咱們的感受要快,看上去就是在同一時刻運行。
其實,多線程程序並不能提升程序的運行速度,但可以提升程序運行效率,讓CPU的使用率更高。java
代碼示例:瀏覽器
public class Demo { public static void main(String[] args) { fun(); System.out.println(Math.abs(-9)); } public static void fun() { for(int i=0;i<10000; i++) { System.out.println(i); } } }
當在某個線程中運行的代碼建立一個新的Thread對象時,新線程的優先級最初設置爲等於建立線程的優先級,而且當且僅當建立線程是守護進程時纔是守護進程線程。安全
經常使用構造方法多線程
Thread() Allocates a new Thread object. Thread(Runnable target) Allocates a new Thread object. Thread(Runnable target, String name) Allocates a new Thread object. Thread(String name) Allocates a new Thread object.
經常使用方法併發
一種方法是將類聲明爲 Thread 的子類。該子類應重寫 Thread 類的 run 方法。建立對象,開啓線程。run方法至關於其餘線程的main方法。異步
``` class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
```jvm
另外一種方法是聲明一個實現 Runnable 接口的類。該類而後實現 run 方法。而後建立Runnable的子類對象,傳入到某個線程的構造方法中,開啓線程。編輯器
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }
代碼示例:ide
public class SubThread extends Thread { @Override public void run() { for(int i=0; i<50; i++) { System.out.println("run方法中的變量:"+i); } } } public class ThreadDemo { public static void main(String[] args) { // 一、JVM從入口main開始執行主線程,從CPU開啓第一條線程路徑,執行main()方法。 SubThread subThread = new SubThread(); // 二、建立線程對象,至關於開啓了一個新的線程,從CPU開啓第二條線程路徑,執行run()方法。 subThread.start(); // 三、執行start方法時,調用run()方法,與main()方法同時要調用CPU,兩個執行路徑都會被CPU執行,CPU本身選擇的權利,出現執行結果,隨機性結果。 for(int i=0; i<50; i++) { System.out.println("main方法中的變量:"+i); } } }
Thread t1 = new Thread();t1.start();
Java API 中函數
String getName() // 返回線程的名字 static Thread currentThread() // 獲取當前線程
示例:
public class NameThread extends Thread { @Override public void run() { System.out.println(super.getName()); // 輸出本線程的名字 } } /* * 每一個線程都有本身的名字 * 運行方法main線程的名字是"main" * 其餘線程也有名字,默認爲"Thread-0","Thread-1", ... * 得到主線程的名字的方法:JVM開啓主線程,運行方法main,主線程也是線程,是線程必然是Thread類的對象,Thread類中的靜態方法: * static Thread currentThread() 返回正在執行的線程對象 * 該對象調用getName方法,獲取線程名字 */ public class ThreadDemo2 { public static void main(String[] args) { NameThread nameThread = new NameThread(); nameThread.start(); // 獲取主線程的線程名 System.out.println(Thread.currentThread().getName()); } }
Java API 中
Thread(String name) // 分配一個新的名字爲name的對象 void setName(String name) // 改變線程的名字爲name
方法一:
// 在主線程中 NameThread nameThread = new NameThread(); nameThread.setName("Thread線程名字");
方法二:
// 在建立的線程類中的run方法中,調用Thread父類構造函數 super("Thread線程名字");
代碼:
public class SleepThread extends Thread{ @Override public void run() { for(int i=0; i<5; i++) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } } } public class ThreadDemo { public static void main(String[] args) throws InterruptedException { SleepThread sleepThread = new SleepThread(); sleepThread.start(); Thread.sleep(2000); } }
建立線程的另外一種方法是聲明實現 Runnable 接口的類。該類而後實現 run 方法。而後建立Runnable的子類對象,傳入到某個線程的構造方法中,開啓線程。
爲什麼要實現Runnable接口,Runable是啥玩意呢?繼續API搜索。
查看Runnable接口說明文檔:Runnable接口用來指定每一個線程要執行的任務。包含了一個 run 的無參數抽象方法,須要由接口實現類重寫該方法。
Java API 中
// Runnable接口中只有一個run方法 // 方法摘要 void run() // 當使用實現接口Runnable的對象來建立線程時,啓動該線程會致使在該單獨執行的線程中調用該對象的run方法。 // 建立線程使用Thread類中的構造方法: Thread(Runnable target) // 分配一個線程對象,參數爲Runnable接口實現類的對象
示例:
public class SubRunnable implements Runnable{ @Override public void run() { for(int i=0; i<50; i++) { System.out.println("run..."+i); } } } /** * 實現接口方式的線程 * 建立Thread類對象,構造方法中,傳遞Runnable接口實現類對象 * 調用Thread類的方法start */ public class RunnableDemo { public static void main(String[] args) { SubRunnable subRunnable = new SubRunnable(); Thread t = new Thread(subRunnable); t.start(); for(int i=0; i<50; i++) { System.out.println("main..."+i); } } }
線程狀態圖:
線程池示意圖:
- 在java中,若是每一個請求到達就建立一個新線程,開銷是至關大的。在實際使用中,建立和銷燬線程花費的時間和消耗的系統資源都至關大,甚至可能要比在處理實際的用戶請求的時間和資源要多的多。除了建立和銷燬線程的開銷以外,活動的線程也須要消耗系統資源。若是在一個JVM裏建立太多的線程,可能會使系統因爲過分消耗內存或「切換過分」而致使系統資源不足。爲了防止資源不足,須要採起一些
辦法來限制任何給定時刻處理的請求數目,儘量減小建立和銷燬線程的次數,特別是一些資源耗費比較大的線程的建立和銷燬,儘可能利用已有對象來進行服務。
- 線程池主要用來解決線程生命週期開銷問題和資源不足問題。經過對多個任務重複使用線程,線程建立的開銷就被分攤到了多個任務上了,並且因爲在請求到達時線程已經存在,因此消除了線程建立所帶來的延遲。這樣,就能夠當即爲請求服務,使用應用程序響應更快。另外,經過適當的調整線程中的線程數目能夠防止出現資源不足的狀況。
本身建立線程池(僞代碼示例)
ArrayList<Thread> threads = new ArrayList<Thread>(); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); threads.add(new Thread()); // 程序一開始的時候,建立多個線程對象,存儲到集合中,須要線程,從集合中獲取線程出來 Thread t = threads.remove(0); // 使用線程 t.start(); // 線程用完,回到容器中繼續等待使用 threads.add(t);
從JDK5開始,內置線程池技術,不須要本身建立,直接使用便可。
示例:
public class ThreadPoolRunnable implements Runnable{ @Override public void run() { System.out.println(new Thread().getName()); } } import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /* * JDK1.5以後的新特性,實現線程池程序 * 一、使用工廠類,Executors中的靜態方法建立線程對象,指定線程個數 * 二、static ExecutorsService newFixedThreadPool(int 線程個數) 返回線程池對象 * 三、返回的是 ExecutorsService接口的實現類(線程池對象) * 四、接口實現類對象,調用方法submit(Runnable r) 提交線程,執行任務 */ public class ThreadPoolDemo { public static void main(String[] args) { // 調用工廠類的靜態方法,建立線程池對象 // Executors.newFixedThreadPool(2);返回線程池對象,是接口的實現類對象 ExecutorService es = Executors.newFixedThreadPool(2); // 調用接口實現類對象es的方法submit,提交一個線程任務 es.submit(new ThreadPoolRunnable()); es.submit(new ThreadPoolRunnable()); es.submit(new ThreadPoolRunnable()); } }
<T> Future<T> submit(Callable<T> task)
:獲取線程池中的某一個線程對象,並執行線程中的call()方法示例:
import java.util.concurrent.Callable; public class ThreadPoolCallable implements Callable<String>{ @Override public String call() throws Exception { return "abc"; } } import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(2); // 提交任務的方法,返回Future接口的實現類 Future<String> f = es.submit(new ThreadPoolCallable()); String s = f.get(); System.out.println(s); } }
``` import java.util.concurrent.Callable; /* * 多線程的異步計算 * */ public class GetSumCallable implements Callable<Integer>{ private int a; public GetSumCallable(int a) { this.a = a; } @Override public Integer call() throws Exception { int sum = 0; for(int i=0; i<=a; i++) { sum += i; } return sum; } } import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(2); Future<Integer> f1 = es.submit(new GetSumCallable(100)); // 加法 Future<Integer> f2 = es.submit(new GetSumCallable(200)); // 減法 System.out.println("1+2+...+100 = "+f1.get()); System.out.println("1+2+...+200 = "+f2.get()); es.shutdown(); } } ```