java線程使用
① java中如何啟動一個新的線程
java開啟新線程的三種方法:
方法1:繼承Thread類
1):定義一個繼承自Java.lang.Thread類的類A.
2):覆蓋A類Thread類中的run方法。
3):我們編寫需要在run方法中執行的操作:run方法中的代碼,線程執行體。
4):在main方法(線程)中,創建一個線程對象並啟動線程。
(1)創建線程類對象:
A類 a = new A類();
(2)調用線程對象的start方法:
a.start();//啟動一個線程
注意:不要調用run方法。如果run方法被稱為對象調用方法,則仍然只有一個線程,並且沒有啟動新線程。
創建啟動線程實例:
(1)java線程使用擴展閱讀:
啟動新線程的兩種方式對比
繼承方式:
1):從設計上分析,Java中類是單繼承的,如果繼承了Thread了,該類就不能再有其他的直接父類了.
2):從操作上分析,繼承方式更簡單,獲取線程名字也簡單.(操作上,更簡單)
3):從多線程共享同一個資源上分析,繼承方式不能做到.
實現方式:
1):從設計上分析,Java中類可以多實現介面,此時該類還可以繼承其他類,並且還可以實現其他介面,設計更為合理.
2):從操作上分析,實現方式稍微復雜點,獲取線程名字也比較復雜,得使用Thread.currentThread()來獲取當前線程的引用.
3):從多線程共享同一個資源上分析,實現方式可以做到(是否共享同一個資源).
補充:實現方式獲取線程名字:
String name = Thread.currentThread().getName();
② java多線程用在快遞系統中能做什麼
Java 多線程可以在快遞系統中用來執行多個任務並發地。這樣就可以提升系統的效率,同時也能更好地利用計算機的多核處理能力。
例如,在快遞系統中,你可以使用多線程來並發地處理不同的訂單。在一個線程中處理一個訂單的列印工作,在另一個線程中處理另一個訂單的裝袋工作,以此類推。這樣就可以讓系統在同一時間內處理更多的訂單,從而提升效現。
此外,你還可以使用多線程來實現更復雜的功能,例如路徑規劃、貨物追蹤等。總的來說,Java 多線程在快遞系統中有很多的應用場景,可以幫助你實現更高效、更靈活的系統。
③ 在Java 中多線程的實現方法有哪些,如何使用
1、 認識Thread和Runnable
Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable介面。Runnable是介面,建議用介面的方式生成線程,因為介面可以實現多繼承,況且Runnable只有一個run方法,很適合繼承。在使用Thread的時候只需繼承Thread,並且new一個實例出來,調用start()方法即可以啟動一個線程。
Thread Test = new Thread();
Test.start();
在使用Runnable的時候需要先new一個實現Runnable的實例,之後啟動Thread即可。
Test impelements Runnable;
Test t = new Test();
Thread test = new Thread(t);
test.start();
總結:Thread和Runnable是實現java多線程的2種方式,runable是介面,thread是類,建議使用runable實現java多線程,不管如何,最終都需要通過thread.start()來使線程處於可運行狀態。
2、 認識Thread的start和run
1) start:
用start方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啟動一個線程,這時此線程處於就緒(可運行)狀態,並沒有運行,一旦得到spu時間片,就開始執行run()方法,這里方法run()稱為線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。
2) run:
run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是只有一條,還是要順序執行,還是要等待run方法體執行完畢後才可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。
總結:調用start方法方可啟動線程,而run方法只是thread的一個普通方法調用,還是在主線程里執行。
3、 線程狀態說明
線程狀態從大的方面來說,可歸結為:初始狀態、可運行狀態、不可運行狀態和消亡狀態,具體可細分為上圖所示7個狀態,說明如下:
1) 線程的實現有兩種方式,一是繼承Thread類,二是實現Runnable介面,但不管怎樣,當我們new了thread實例後,線程就進入了初始狀態;
2) 當該對象調用了start()方法,就進入可運行狀態;
3) 進入可運行狀態後,當該對象被操作系統選中,獲得CPU時間片就會進入運行狀態;
4) 進入運行狀態後case就比較多,大致有如下情形:
·run()方法或main()方法結束後,線程就進入終止狀態;
·當線程調用了自身的sleep()方法或其他線程的join()方法,就會進入阻塞狀態(該狀態既停止當前線程,但並不釋放所佔有的資源)。當sleep()結束或join()結束後,該線程進入可運行狀態,繼續等待OS分配時間片;
·當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被鎖牢(synchroniza,lock),將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池裡也許已經有了其他線程在等待獲取鎖標記,這時它們處於隊列狀態,既先到先得),一旦線程獲得鎖標記後,就轉入可運行狀態,等待OS分配CPU時間片;
·當線程調用wait()方法後會進入等待隊列(進入這個狀態會釋放所佔有的所有資源,與阻塞狀態不同),進入這個狀態後,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒(由於notify()只是喚醒一個線程,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒有所線程),線程被喚醒後會進入鎖池,等待獲取鎖標記。
·當線程調用stop方法,即可使線程進入消亡狀態,但是由於stop方法是不安全的,不鼓勵使用,大家可以通過run方法里的條件變通實現線程的stop。
④ Java線程池使用時需要注意的幾點
<1>.不要調用Thread類或Runnable對象的run方法。直接調用run方法只會執行同一個線程中的任務,而不會啟動新的線程。應該調用Thread.start方法。這個方法將創建一個執行run方法的新線程。
<2>.interrupted和isInterrupted是兩個非常相似的方法。interrupted方法是一個靜態的方法。它檢測當前的線程是否被中斷。而且,會清除該線程的中斷狀態。
isInterrupted方法是一個實例方法。可用來檢驗是否有線程中斷。調用這個方法不會改變中斷狀態。
<3>.interruptedException的catch字句做一些處理有什麼好處的話。仍然有兩種合理的選擇。
void mySubTask()
{...
try{sleep(delay);}
catch(InterruptedException e) {Thread().currentThread().interrupt();}
....
}
或者用throws interruptedException標記的方法。
⑤ java中學習線程應該怎麼去學習
打個比方,用戶注冊,如果用戶注冊有如下步驟
1:給用戶在資料庫中添加用戶信息
2:給用戶的手機號發送歡迎簡訊
3:系統中其它模塊和用戶關聯,需要同時添加其它的數據
這個時候,如果使用單線程,用戶提交注冊信息之後,系統拿到注冊信息,就要按照步驟1,2,3這么一步一步走下去,在這過程中,用戶只能等待,等到系統把這些步驟走完了,用戶才能得到響應,才能登陸系統,這個過程會很長,用戶體驗不好
但是如果使用多線程,在拿到用戶注冊信息之後,主進程把這些任務分給多個線程去做,每個線程做一件事,效率是不是提高了,時間是不是縮短了,並且,主線程可以把關鍵信息錄入系統之後就直接響應用戶,其它事情可以讓線程在後台慢慢執行,這樣用戶體驗就會好很多。
⑥ java線程池(一) 簡述線程池的幾種使用方式
首先說明下java線程是如何實現線程重用的
1. 線程執行完一個Runnable的run()方法後,不會被殺死
2. 當線程被重用時,這個線程會進入新Runnable對象的run()方法12
java線程池由Executors提供的幾種靜態方法創建線程池。下面通過代碼片段簡單介紹下線程池的幾種實現方式。後續會針對每個實現方式做詳細的說明
newFixedThreadPool
創建一個固定大小的線程池
添加的任務達到線程池的容量之後開始加入任務隊列開始線程重用總共開啟線程個數跟指定容量相同。
@Test
public void newFixedThreadPool() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService = Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().build());
RunThread run1 = new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}12345678
newSingleThreadExecutor
僅支持單線程順序處理任務
@Test
public void newSingleThreadExecutor() throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}123456789
newCachedThreadPool
這種情況跟第一種的方式類似,不同的是這種情況線程池容量上線是Integer.MAX_VALUE 並且線程池開啟緩存60s
@Test
public void newCachedThreadPool() throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService = Executors.newCachedThreadPool(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}123456789
newWorkStealingPool
支持給定的並行級別,並且可以使用多個隊列來減少爭用。
@Test
public void newWorkStealingPool() throws Exception {
ExecutorService executorService = Executors.newWorkStealingPool();
executorService = Executors.newWorkStealingPool(1);
RunThread run1 = new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}123456789
newScheledThreadPool
看到的現象和第一種相同,也是在線程池滿之前是新建線程,然後開始進入任務隊列,進行線程重用
支持定時周期執行任務(還沒有看完)
@Test
public void newScheledThreadPool() throws Exception {
ExecutorService executorService = Executors.newScheledThreadPool(1);
executorService = Executors.newScheledThreadPool(1, new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}
⑦ 在java中啟動線程使用run()還是start()
啟動一個線程用start()方法,使線程所代表的虛擬處理機處於可運行的狀態,這意味著它可以有JVM(java虛擬機)來調度和執行,這並不意味著線程就會立即執行。run()方法可以產生必須退出的標志來停止一個線程。
⑧ 在Java 中多線程的實現方法有哪些,如何使用
Java多線程的創建及啟動
Java中線程的創建常見有如三種基本形式
1.繼承Thread類,重寫該類的run()方法。
復制代碼
1 class MyThread extends Thread {
2
3 private int i = 0;
4
5 @Override
6 public void run() {
7 for (i = 0; i < 100; i++) {
8 System.out.println(Thread.currentThread().getName() + " " + i);
9 }
10 }
11 }
復制代碼
復制代碼
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 System.out.println(Thread.currentThread().getName() + " " + i);
6 if (i == 30) {
7 Thread myThread1 = new MyThread(); // 創建一個新的線程 myThread1 此線程進入新建狀態
8 Thread myThread2 = new MyThread(); // 創建一個新的線程 myThread2 此線程進入新建狀態
9 myThread1.start(); // 調用start()方法使得線程進入就緒狀態
10 myThread2.start(); // 調用start()方法使得線程進入就緒狀態
11 }
12 }
13 }
14 }
復制代碼
如上所示,繼承Thread類,通過重寫run()方法定義了一個新的線程類MyThread,其中run()方法的方法體代表了線程需要完成的任務,稱之為線程執行體。當創建此線程類對象時一個新的線程得以創建,並進入到線程新建狀態。通過調用線程對象引用的start()方法,使得該線程進入到就緒狀態,此時此線程並不一定會馬上得以執行,這取決於CPU調度時機。
2.實現Runnable介面,並重寫該介面的run()方法,該run()方法同樣是線程執行體,創建Runnable實現類的實例,並以此實例作為Thread類的target來創建Thread對象,該Thread對象才是真正的線程對象。
復制代碼
1 class MyRunnable implements Runnable {
2 private int i = 0;
3
4 @Override
5 public void run() {
6 for (i = 0; i < 100; i++) {
7 System.out.println(Thread.currentThread().getName() + " " + i);
8 }
9 }
10 }
復制代碼
復制代碼
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 System.out.println(Thread.currentThread().getName() + " " + i);
6 if (i == 30) {
7 Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象
8 Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創建新的線程
9 Thread thread2 = new Thread(myRunnable);
10 thread1.start(); // 調用start()方法使得線程進入就緒狀態
11 thread2.start();
12 }
13 }
14 }
15 }
復制代碼
相信以上兩種創建新線程的方式大家都很熟悉了,那麼Thread和Runnable之間到底是什麼關系呢?我們首先來看一下下面這個例子。
復制代碼
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 System.out.println(Thread.currentThread().getName() + " " + i);
6 if (i == 30) {
7 Runnable myRunnable = new MyRunnable();
8 Thread thread = new MyThread(myRunnable);
9 thread.start();
10 }
11 }
12 }
13 }
14
15 class MyRunnable implements Runnable {
16 private int i = 0;
17
18 @Override
19 public void run() {
20 System.out.println("in MyRunnable run");
21 for (i = 0; i < 100; i++) {
22 System.out.println(Thread.currentThread().getName() + " " + i);
23 }
24 }
25 }
26
27 class MyThread extends Thread {
28
29 private int i = 0;
30
31 public MyThread(Runnable runnable){
32 super(runnable);
33 }
34
35 @Override
36 public void run() {
37 System.out.println("in MyThread run");
38 for (i = 0; i < 100; i++) {
39 System.out.println(Thread.currentThread().getName() + " " + i);
40 }
41 }
42 }
復制代碼
同樣的,與實現Runnable介面創建線程方式相似,不同的地方在於
1 Thread thread = new MyThread(myRunnable);
那麼這種方式可以順利創建出一個新的線程么?答案是肯定的。至於此時的線程執行體到底是MyRunnable介面中的run()方法還是MyThread類中的run()方法呢?通過輸出我們知道線程執行體是MyThread類中的run()方法。其實原因很簡單,因為Thread類本身也是實現了Runnable介面,而run()方法最先是在Runnable介面中定義的方法。
1 public interface Runnable {
2
3 public abstract void run();
4
5 }
我們看一下Thread類中對Runnable介面中run()方法的實現:
復制代碼
@Override
public void run() {
if (target != null) {
target.run();
}
}
復制代碼
也就是說,當執行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執行target中的run()方法,也就是實現了Runnable介面並重寫了run()方法的類中的run()方法。但是上述給到的列子中,由於多態的存在,根本就沒有執行到Thread類中的run()方法,而是直接先執行了運行時類型即MyThread類中的run()方法。
3.使用Callable和Future介面創建線程。具體是創建Callable介面的實現類,並實現clall()方法。並使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象作為Thread對象的target來創建線程。
看著好像有點復雜,直接來看一個例子就清晰了。
復制代碼
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4
5 Callable<Integer> myCallable = new MyCallable(); // 創建MyCallable對象
6 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask來包裝MyCallable對象
7
8 for (int i = 0; i < 100; i++) {
9 System.out.println(Thread.currentThread().getName() + " " + i);
10 if (i == 30) {
11 Thread thread = new Thread(ft); //FutureTask對象作為Thread對象的target創建新的線程
12 thread.start(); //線程進入到就緒狀態
13 }
14 }
15
16 System.out.println("主線程for循環執行完畢..");
17
18 try {
19 int sum = ft.get(); //取得新創建的新線程中的call()方法返回的結果
20 System.out.println("sum = " + sum);
21 } catch (InterruptedException e) {
22 e.printStackTrace();
23 } catch (ExecutionException e) {
24 e.printStackTrace();
25 }
26
27 }
28 }
29
30
31 class MyCallable implements Callable<Integer> {
32 private int i = 0;
33
34 // 與run()方法不同的是,call()方法具有返回值
35 @Override
36 public Integer call() {
37 int sum = 0;
38 for (; i < 100; i++) {
39 System.out.println(Thread.currentThread().getName() + " " + i);
40 sum += i;
41 }
42 return sum;
43 }
44
45 }
復制代碼
首先,我們發現,在實現Callable介面中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執行體,同時還具有返回值!在創建新的線程時,是通過FutureTask來包裝MyCallable對象,同時作為了Thread對象的target。那麼看下FutureTask類的定義:
1 public class FutureTask<V> implements RunnableFuture<V> {
2
3 //....
4
5 }
1 public interface RunnableFuture<V> extends Runnable, Future<V> {
2
3 void run();
4
5 }
於是,我們發現FutureTask類實際上是同時實現了Runnable和Future介面,由此才使得其具有Future和Runnable雙重特性。通過Runnable特性,可以作為Thread對象的target,而Future特性,使得其可以取得新創建線程中的call()方法的返回值。
執行下此程序,我們發現sum = 4950永遠都是最後輸出的。而「主線程for循環執行完畢..」則很可能是在子線程循環中間輸出。由CPU的線程調度機制,我們知道,「主線程for循環執行完畢..」的輸出時機是沒有任何問題的,那麼為什麼sum =4950會永遠最後輸出呢?
原因在於通過ft.get()方法獲取子線程call()方法的返回值時,當子線程此方法還未執行完畢,ft.get()方法會一直阻塞,直到call()方法執行完畢才能取到返回值。
上述主要講解了三種常見的線程創建方式,對於線程的啟動而言,都是調用線程對象的start()方法,需要特別注意的是:不能對同一線程對象兩次調用start()方法。
你好,本題已解答,如果滿意
請點右下角「採納答案」。
⑨ java中的線程一般是用來做什麼
線程可以調起一個任務,用來做事情的,可以同時喚起多個線程,叫多線程