Java多線程的創(chuàng)建及啟動
創(chuàng)新互聯(lián)建站是一家專注網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、小程序定制開發(fā)、電子商務(wù)建設(shè)、網(wǎng)絡(luò)推廣、移動互聯(lián)開發(fā)、研究、服務(wù)為一體的技術(shù)型公司。公司成立十年以來,已經(jīng)為近千家成都廣告推廣各業(yè)的企業(yè)公司提供互聯(lián)網(wǎng)服務(wù)?,F(xiàn)在,服務(wù)的近千家客戶與我們一路同行,見證我們的成長;未來,我們一起分享成功的喜悅。
Java中線程的創(chuàng)建常見有如三種基本形式
1.繼承Thread類,重寫該類的run()方法。
復(fù)制代碼
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 }
復(fù)制代碼
復(fù)制代碼
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(); ? ? // 創(chuàng)建一個新的線程 ?myThread1 ?此線程進(jìn)入新建狀態(tài)
8 ? ? ? ? ? ? ? ? Thread myThread2 = new MyThread(); ? ? // 創(chuàng)建一個新的線程 myThread2 此線程進(jìn)入新建狀態(tài)
9 ? ? ? ? ? ? ? ? myThread1.start(); ? ? ? ? ? ? ? ? ? ? // 調(diào)用start()方法使得線程進(jìn)入就緒狀態(tài)
10 ? ? ? ? ? ? ? ? myThread2.start(); ? ? ? ? ? ? ? ? ? ? // 調(diào)用start()方法使得線程進(jìn)入就緒狀態(tài)
11 ? ? ? ? ? ? }
12 ? ? ? ? }
13 ? ? }
14 }
復(fù)制代碼
如上所示,繼承Thread類,通過重寫run()方法定義了一個新的線程類MyThread,其中run()方法的方法體代表了線程需要完成的任務(wù),稱之為線程執(zhí)行體。當(dāng)創(chuàng)建此線程類對象時一個新的線程得以創(chuàng)建,并進(jìn)入到線程新建狀態(tài)。通過調(diào)用線程對象引用的start()方法,使得該線程進(jìn)入到就緒狀態(tài),此時此線程并不一定會馬上得以執(zhí)行,這取決于CPU調(diào)度時機。
2.實現(xiàn)Runnable接口,并重寫該接口的run()方法,該run()方法同樣是線程執(zhí)行體,創(chuàng)建Runnable實現(xiàn)類的實例,并以此實例作為Thread類的target來創(chuàng)建Thread對象,該Thread對象才是真正的線程對象。
復(fù)制代碼
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 }
復(fù)制代碼
復(fù)制代碼
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(); // 創(chuàng)建一個Runnable實現(xiàn)類的對象
8 ? ? ? ? ? ? ? ? Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創(chuàng)建新的線程
9 ? ? ? ? ? ? ? ? Thread thread2 = new Thread(myRunnable);
10 ? ? ? ? ? ? ? ? thread1.start(); // 調(diào)用start()方法使得線程進(jìn)入就緒狀態(tài)
11 ? ? ? ? ? ? ? ? thread2.start();
12 ? ? ? ? ? ? }
13 ? ? ? ? }
14 ? ? }
15 }
復(fù)制代碼
相信以上兩種創(chuàng)建新線程的方式大家都很熟悉了,那么Thread和Runnable之間到底是什么關(guān)系呢?我們首先來看一下下面這個例子。
復(fù)制代碼
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 }
復(fù)制代碼
同樣的,與實現(xiàn)Runnable接口創(chuàng)建線程方式相似,不同的地方在于
1 Thread thread = new MyThread(myRunnable);
那么這種方式可以順利創(chuàng)建出一個新的線程么?答案是肯定的。至于此時的線程執(zhí)行體到底是MyRunnable接口中的run()方法還是MyThread類中的run()方法呢?通過輸出我們知道線程執(zhí)行體是MyThread類中的run()方法。其實原因很簡單,因為Thread類本身也是實現(xiàn)了Runnable接口,而run()方法最先是在Runnable接口中定義的方法。
1 public interface Runnable {
2 ?
3 ? ? public abstract void run();
4 ?
5 }
我們看一下Thread類中對Runnable接口中run()方法的實現(xiàn):
復(fù)制代碼
@Override
public void run() {
if (target != null) {
target.run();
}
}
復(fù)制代碼
也就是說,當(dāng)執(zhí)行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執(zhí)行target中的run()方法,也就是實現(xiàn)了Runnable接口并重寫了run()方法的類中的run()方法。但是上述給到的列子中,由于多態(tài)的存在,根本就沒有執(zhí)行到Thread類中的run()方法,而是直接先執(zhí)行了運行時類型即MyThread類中的run()方法。
3.使用Callable和Future接口創(chuàng)建線程。具體是創(chuàng)建Callable接口的實現(xiàn)類,并實現(xiàn)clall()方法。并使用FutureTask類來包裝Callable實現(xiàn)類的對象,且以此FutureTask對象作為Thread對象的target來創(chuàng)建線程。
看著好像有點復(fù)雜,直接來看一個例子就清晰了。
復(fù)制代碼
1 public class ThreadTest {
2
3 ? ? public static void main(String[] args) {
4
5 ? ? ? ? CallableInteger myCallable = new MyCallable(); ? ?// 創(chuàng)建MyCallable對象
6 ? ? ? ? FutureTaskInteger ft = new FutureTaskInteger(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創(chuàng)建新的線程
12 ? ? ? ? ? ? ? ? thread.start(); ? ? ? ? ? ? ? ? ? ? ?//線程進(jìn)入到就緒狀態(tài)
13 ? ? ? ? ? ? }
14 ? ? ? ? }
15
16 ? ? ? ? System.out.println("主線程for循環(huán)執(zhí)行完畢..");
17 ? ? ?
18 ? ? ? ? try {
19 ? ? ? ? ? ? int sum = ft.get(); ? ? ? ? ? ?//取得新創(chuàng)建的新線程中的call()方法返回的結(jié)果
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 CallableInteger {
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 }
復(fù)制代碼
首先,我們發(fā)現(xiàn),在實現(xiàn)Callable接口中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執(zhí)行體,同時還具有返回值!在創(chuàng)建新的線程時,是通過FutureTask來包裝MyCallable對象,同時作為了Thread對象的target。那么看下FutureTask類的定義:
1 public class FutureTaskV implements RunnableFutureV {
2 ?
3 ? ? //....
4 ?
5 }
1 public interface RunnableFutureV extends Runnable, FutureV {
2 ?
3 ? ? void run();
4 ?
5 }
于是,我們發(fā)現(xiàn)FutureTask類實際上是同時實現(xiàn)了Runnable和Future接口,由此才使得其具有Future和Runnable雙重特性。通過Runnable特性,可以作為Thread對象的target,而Future特性,使得其可以取得新創(chuàng)建線程中的call()方法的返回值。
執(zhí)行下此程序,我們發(fā)現(xiàn)sum = 4950永遠(yuǎn)都是最后輸出的。而“主線程for循環(huán)執(zhí)行完畢..”則很可能是在子線程循環(huán)中間輸出。由CPU的線程調(diào)度機制,我們知道,“主線程for循環(huán)執(zhí)行完畢..”的輸出時機是沒有任何問題的,那么為什么sum =4950會永遠(yuǎn)最后輸出呢?
原因在于通過ft.get()方法獲取子線程call()方法的返回值時,當(dāng)子線程此方法還未執(zhí)行完畢,ft.get()方法會一直阻塞,直到call()方法執(zhí)行完畢才能取到返回值。
上述主要講解了三種常見的線程創(chuàng)建方式,對于線程的啟動而言,都是調(diào)用線程對象的start()方法,需要特別注意的是:不能對同一線程對象兩次調(diào)用start()方法。
你好,本題已解答,如果滿意
請點右下角“采納答案”。
package threadgroup;
class ThreadDemo3 extends Thread {
private String name;
private int delay;
public ThreadDemo3(String sname, int i_delay) {
name = sname;
delay = i_delay;
}
public void run() {
try {
sleep(delay);
} catch (InterruptedException e) {
}
System.out.println("多線程測試!\n" + name + "\n" + delay);
}
}
public class testMyThread {
public static void main(String[] args) {
ThreadDemo3 th1,th2,th3;
th1 = new ThreadDemo3("線程1", (int) (Math.random() * 900));
th2 = new ThreadDemo3("線程2", (int) (Math.random() * 900));
th3 = new ThreadDemo3("線程3", (int) (Math.random() * 900));
th1.start();
th2.start();
th3.start();
}
}
package threadgroup;
public class threadDemo {
public static void main(String[] args) {
Thread t = Thread.currentThread();
t.setName("你好嗎?");
System.out.println("正在進(jìn)行的Thread是:" + t);
try {
for (int i = 0; i 5; i++) {
System.out.println("我不叫穆繼超" + i);
Thread.sleep(3000);
}
} catch (Exception e) {
// TODO: handle exception
System.out.println("Thread has wrong" + e.getMessage());
}
}
}
package threadgroup;
public class threadDemo2 implements Runnable {
public threadDemo2() {
Thread t1 = Thread.currentThread();
t1.setName("第一個主進(jìn)程");
System.out.println("正在運行" + t1);
Thread t2 = new Thread(this, "");
System.out.println("在創(chuàng)建一個進(jìn)程");
t2.start();
try {
System.out.println("使他進(jìn)入第一個睡眠狀態(tài)");
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Thread has wrong" + e.getMessage());
}
System.out.println("退出第一個進(jìn)程");
}
public void run() {
try {
for (int i = 0; i 5; i++) {
System.out.println("進(jìn)程" + i);
Thread.sleep(3000);
}
} catch (InterruptedException e) {
// TODO: handle exception
System.out.println("Thread has wrong" + e.getMessage());
}
System.out.println("退出第二個進(jìn)程");
}
public static void main(String[] args) {
new threadDemo2();
}
}
多進(jìn)程是指操作系統(tǒng)能同時運行多個任務(wù)(程序),多線程是指在同一程序中有多個順序流在執(zhí)行。
在java中創(chuàng)建一個線程有兩種方法:
package?com.thread;
public?class?ThreadTest1?{
public?static?void?main(String[]?args)?{
Runnable1?r?=?new?Runnable1();
//r.run();并不是線程開啟,而是簡單的方法調(diào)用
Thread?t?=?new?Thread(r);//創(chuàng)建線程
//t.run();?//如果該線程是使用獨立的?Runnable?運行對象構(gòu)造的,則調(diào)用該?Runnable?對象的?run?方法;否則,該方法不執(zhí)行任何操作并返回。
t.start();?//線程開啟
for?(int?i?=?0;?i??100;?i++)?{
System.out.println("main:"+i);
}
}
}
class?Runnable1?implements?Runnable{
public?void?run()?{
for?(int?i?=?0;?i??100;?i++)?{
System.out.println("Thread-----:"+i);
}
}
}
因為你new了兩次
試著在Task類內(nèi)創(chuàng)建一個對象 然后鎖住這個對象
1、java多線程調(diào)用同步方法時主程序或者后臺服務(wù)Service程序兩者必須有一個正在運行著,定時任務(wù)才會執(zhí)行。
2、自動執(zhí)行的任務(wù)可以設(shè)置開啟或關(guān)閉定時,檢查任務(wù)的這一開關(guān)處于開啟狀態(tài)。
3、源目錄在定時的時間點如果沒有變化,任務(wù)執(zhí)行后不會留下日志,通過查看任務(wù)的最后執(zhí)行時間確定任務(wù)到底執(zhí)行了沒有。
4、執(zhí)行失敗和沒有執(zhí)行不是同一回事,如果是執(zhí)行失敗則要分析失敗原因。這是java多線程調(diào)用同步方法時,休眠后代碼執(zhí)行不到的原因。
線程用到Thread或者Runnable接口(Thread也操作了Runnable接口)
繼承了Thread類后需要重載其run方法,在方法里寫你需要完成的事情,開始線程是調(diào)用其start方法。
操作Runnable接口必須實現(xiàn)其run方法,在方法里寫你需要完成的事情,Runnable接口沒有start方法,所以啟動線程還是需要依靠Thread類 new Thread(Runnable runnable).start();
一般項目中多是操作接口,因為類只能單繼承,接口可以操作多個。
網(wǎng)站欄目:java調(diào)用線程代碼 java 線程使用
網(wǎng)頁網(wǎng)址:http://jinyejixie.com/article2/dodpjoc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、Google、虛擬主機、建站公司、用戶體驗、電子商務(wù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)