這篇文章給大家介紹Java線程創建方式有哪些,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
多線程的創建,方式一:繼承于Thread類
1.創建一個繼承于Thread類的子類
2.重寫Thread類的run()--->將此線程執行的操作聲明在run()中
3.創建Thread類的子類的對象
4.通過此對象調用start():
start()方法的兩個作用:
A.啟動當前線程
B.調用當前線程的run()
創建過程中的兩個問題:
問題一:我們不能通過直接調用run()的方式啟動線程
問題二:在啟動一個線程,遍歷偶數,不可以讓已經start()的線程去執行,會報異常;正確的方式是重新創建一個線程的對象。
//1.創建一個繼承于Thread類的子類 class MyThread extends Thread{ //2.重寫Thread類的run() @Override public void run() {//第二個線程 for(int i = 0;i < 10;i++){ if(i % 2 == 0){ System.out.println(i); } } } } public class ThreadTest { public static void main(String[] args) {//主線程 //3.創建Thread類的子類的對象 MyThread t1 = new MyThread(); //4.通過此對象調用start() t1.start(); //問題一:不能通過直接調用run()的方式啟動線程 // t1.run();//錯誤的 //問題二:再啟動一個線程:我們需要再創建 一個對象 //t1.start();//錯誤的 MyThread t2 = new MyThread(); t2.start(); for(int i = 0;i < 10;i++){ if(i % 2 != 0){ System.out.println(i + "****main()******"); } } } }
此代碼在主線程內輸出奇數,在另一個線程里輸出偶數,則輸出結果應該是兩個輸出結果是交互的。
1****main()******
3****main()******
5****main()******
7****main()******
0
2
4
6
8
9****main()******
class Window extends Thread{//創建三個窗口賣票, 總票數為100張,使用繼承于Thread類的方式 private static int ticket = 100;//三個窗口共享:聲明為static @Override public void run() { while(true){ if(ticket > 0){ System.out.println(getName() + ":賣票,票號為:" + ticket); ticket--; }else{ break; } } } } public class WindowTest2 { public static void main(String[] args) { Window t1 = new Window(); Window t2 = new Window(); Window t3 = new Window(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }
public class ThreadDemo { public static void main(String[] args) { // MyThread1 m1 = new MyThread1(); // MyThread2 m2 = new MyThread2(); // m1.start(); // m2.start(); //由于造的類只創建過一次對象,后面就不用了,可以考慮使用匿名類的方式 //創建Thread類的匿名子類的方式 new Thread(){ @Override public void run() { for(int i = 0;i < 100;i++){ if(i % 2 == 0){ System.out.println(i); } } } }.start(); new Thread(){ @Override public void run() { for(int i = 0;i < 100;i++){ if(i % 2 != 0){ System.out.println(i); } } } }.start(); } } class MyThread1 extends Thread{ @Override public void run() { for(int i = 0;i < 100;i++){ if(i % 2 == 0){ System.out.println(i); } } } } class MyThread2 extends Thread{ @Override public void run() { for(int i = 0;i < 100;i++){ if(i % 2 != 0){ System.out.println(i); } } } }
創建多線程的方式二:實現Runnable接口
創建一個實現了Runnable接口的類
實現類去實現Runnable中的抽象方法:run()
創建實現類的對象
將此對象作為參數傳遞到Thread類的構造器中,創建Thread類的對象
通過Thread類的對象調用start()
class MThread implements Runnable{ //2.實現類去實現Runnable中的抽象方法:run() @Override public void run() { for(int i = 0;i < 100;i++){ if (i % 2 == 0) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class ThreadTest1 { public static void main(String[] args) { //3.創建實現類的對象 MThread mThread = new MThread(); //4.將此對象作為參數傳遞到Thread類的構造器中,創建Thread類的對象 Thread t1 = new Thread(mThread); t1.setName("線程1"); //5.通過Thread類的對象調用start():A.啟動線程B.調用當前線程的run()-->調用了Runnable類型的target t1.start(); //再啟動一個線程,遍歷100以內的偶數//只需重新實現步驟4,5即可 Thread t2 = new Thread(mThread); t2.setName("線程2"); t2.start(); } }
class window1 implements Runnable{//創建三個窗口賣票, 總票數為100張,使用實現Runnable接口的方式 private int ticket = 100; Object obj = new Object(); @Override public void run() { while (true){ if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "賣票,票號為:" + ticket); ticket--; } else { break; } } } } public class WindowTest { public static void main(String[] args) { window1 w = new window1();//只造了一個對象,所以100張票共享 Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("線程1"); t2.setName("線程2"); t3.setName("線程3"); t1.start(); t2.start(); t3.start(); } }
與使用Runnable相比,Callable功能更強大些
>相比run()方法,可以有返回值
>方法可以拋出異常
>支持泛型的返回值
>需要借助FutureTask類,比如獲取返回結果
>可以對具體Runnable、Callable任務的執行結果進行取消、查詢是否完成、獲取結果等。
>FutureTask是Futrue接口的唯一的實現類
>FutureTaskb同時實現了Runnable,Future接口。它既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值
//1.創建一個實現Callable的實現類 class NumThread implements Callable{ //2.實現call方法,將此線程需要執行的操作聲明在call()中 @Override public Object call() throws Exception { int sum = 0; for(int i = 1;i <= 100;i++){ if(i % 2 == 0){ System.out.println(i); sum += i; } } return sum;//sum是int,自動裝箱為Integer(Object的子類) } } public class ThreadNew { public static void main(String[] args) { //3.創建Callable接口實現類的對象 NumThread numThread = new NumThread(); //4.將此Callable接口實現類的對象作為參數傳遞到 FutureTask的構造器中,創建FutureTask的對象 FutureTask futureTask = new FutureTask(numThread); //5.將 FutureTask的對象作為參數傳遞到Thread類的構造器中,創建Thread對象,并調用start() new Thread(futureTask).start(); try { //獲取Callable中call()的返回值(不是必須的步驟) //get()返回值即為FutureTask構造器參數Callable實現類重寫的call()的返回值。 Object sum = futureTask.get(); System.out.println("總和為:" + sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
背景:經常創建和銷毀、使用量特別大的資源,比如并發情況下的線程,對性能影響很大。
思路:提前創建好多個線程,放入線程池中,使用時直接獲取,使用完放回池中??梢员苊忸l繁創建銷毀、實現重復利用。類似生活中的公共交通工具。
好處:>提高響應速度(減少了創建新線程的時間)
>降低資源消耗(重復利用線程池中線程,不需要每次都創建)
>便于線程管理:A.corePoolSize:核心池的大小 B.maximumPoolSize:最大線程數 C.keepAliveTime:線程沒有任務時最多保持多長時間后會終止
class NumberThread implements Runnable{ @Override public void run() { for(int i = 0;i <= 100;i++){ if(i % 2 == 0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } } class NumberThread1 implements Runnable{ @Override public void run() { for(int i = 0;i <= 100;i++){ if(i % 2 != 0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class ThreadPool { public static void main(String[] args) { //1.提供指定線程數量的線程池 ExecutorService service = Executors.newFixedThreadPool(10); ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; //設置線程池的屬性 // System.out.println(service.getClass()); // service1.setCorePoolSize(15); // service1.setKeepAliveTime(); //2.執行指定的線程操作。需要提供實現Runnable 接口或Callable接口實現類的對象 service.execute(new NumberThread());//適用于Runnable service.execute(new NumberThread1());//適用于Runnable // service.submit(Callable callable);//適用于Callable //3.關閉連接池 service.shutdown(); } }
開發中:優先選擇:實現Runnable接口的方式
原因:1.實現的方式沒有類的單繼承性的局限性
2.實現的方式更適合來處理多個線程有共享數據的情況。
系:public class Thread implements Runnable
相同點:兩種方式都需要重寫run(),將線程要執行的邏輯聲明在run()中
程序(program)是為完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼,靜態對象。
進程(process)是程序的一次執行過程,或是正在運行的一個程序。是一個動態的過程:有它自身的產生、存在和消亡的過程。---生命周期
線程(thread),進程可進一步細化為線程,是一個程序內部的一條執行路徑。
線程作為調度和執行的單位,每個線程擁有獨立的運行棧和計數器,每個進程擁有獨立的方法區和堆;意味著,多個線程共享一個方法區和堆。而共享的就可以優化,同時,共享的也會帶來安全隱患,這就需要我們解決線程安全問題
背景:以單核CPU為例,只使用單個線程先后完成多個任務(調用多個方法),肯定比用多個線程來完成用的時間更短,為何仍需使用多線程呢?
使用多線程的優點:
1.提高應用程序的響應。對圖形化界面更有意義,可增強用戶體驗。
2.提高計算機系統CPU的利用率
3.改善程序結構。將即長又復雜的線程分為多個線程,獨立運行,利于理解和修改
何時需要多線程
1.程序需要同時執行兩個或多個任務。
2.程序需要實現一些需要等待的任務時,如用戶輸入、文件讀寫操作、網絡操作、搜索等。
3.需要一些后臺運行的程序時。
public class Sample{ public void method1(String str){ System.out.println(str); } public void method2(String str){ method1(str); } public static void main(String[] args){ Sample s = new Sample(); s.method2("hello!"); } }
注意:此程序不是多線程!main方法中調用了method1,method1中又調用了method2;是一條執行路徑,所以是單線程
1.start():啟動當前線程:調用當前線程的run()
2.run():通常需要重寫Thread類中的此方法,將創建的線程要執行的操作聲明在此方法中
3.currentThread():靜態方法,返回執行當前代碼的線程
4.getName():獲取當前線程的名字
5.setName():設置當前線程的名字
6.yield():釋放當前CPU的執行權(下一刻CPU執行的線程仍是隨機的)
>暫停當前正在執行的線程,把執行機會讓給優先級相同或更高的線程
>若隊列中沒有同優先級的線程,忽略此方法
7.join():在線程a中調用線程b的join(),此時,線程a就進入阻塞狀態(停止執行),直到線程b完全執行完以后,線程b才結束阻塞狀態(開始執行)。
8.sleep(long millitime):讓當前線程"睡眠"指定的millitime毫秒。在指定的millitime毫秒時間內,當前線程是阻塞狀態。會拋出InterruptedException異常
* 9.isAlive():判斷當前線程是否存活
class HelloThread extends Thread{ @Override public void run() { for(int i = 0;i < 100;i++){ if(i % 2 != 0){ try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" +Thread.currentThread().getPriority() + ":" + i); } } } public HelloThread(String name){ super(name); } } public class ThreadMethodTest { public static void main(String[] args) { HelloThread h2 = new HelloThread("Thread:1");//通過構造器給線程命名,但前期是得在子類中提供一個構造器 // h2.setName("線程一"); //設置分線程的優先級 h2.setPriority(Thread.MAX_PRIORITY); h2.start(); //給主線程命名 Thread.currentThread().setName("主線程"); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); for(int i = 0;i < 100;i++){ if(i % 2 == 0) { System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i); } // if(i == 20){ // try { // h2.join();//join()的測試 // } catch (InterruptedException e) { // e.printStackTrace(); // } // } } } }
1.MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5--->默認優先級
2.如何獲取和設置當前線程的優先級:
getPriority():獲取線程的優先級
setPriority(int p):設置線程的優先級
說明:高優先級的線程要搶占低優先級線程CPU的執行權,但是只是從概率上講,高優先級的線程高概率的情況下,不一定被執行,并不意味著只有當高優先級的線程執行完畢后,低優先級的線程才執行。
關于Java線程創建方式有哪些就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。