java 多線程的三種構(gòu)建方法
java 多線程的三種構(gòu)建方法
繼承Thread類(lèi)創(chuàng)建線程類(lèi)
public class Thread extends Object implements Runnable
- 定義Thread類(lèi)的子類(lèi),并重寫(xiě)其run()方法
- 創(chuàng)建Thread子類(lèi)的實(shí)例,即創(chuàng)建了線程對(duì)象
- 調(diào)用線程對(duì)象的start()方法啟動(dòng)線程
public class FirstThread extends Thread {
public void run(){
for(int i=0;i<100;i++){
/*
* Thread類(lèi)已經(jīng)繼承了Object
* Object類(lèi)創(chuàng)建了name選項(xiàng) 并且有其getName(),setName()方法
* 在繼承Thread的類(lèi)里面使用時(shí)只需要用this引用
*/
System.out.println(this.getName()+" "+i);
}
}
public static void main(String[] args) {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
new FirstThread().start();
new FirstThread().start();
}
}
}
}
Thread類(lèi)已經(jīng)繼承了Object
Object類(lèi)創(chuàng)建了name選項(xiàng) 并且有其getName(),setName()方法
在繼承Thread的類(lèi)里面使用時(shí)只需要用this引用
上面兩個(gè)副線程和主線程隨機(jī)切換,又因?yàn)槭褂玫氖抢^承Thread的類(lèi)所以?xún)蓚€(gè)副線程不能共享資源
start()方法調(diào)用后并不是立即執(zhí)行多線程代碼,而是使得該線程編程可運(yùn)行狀態(tài),什么時(shí)候運(yùn)行是由操作系統(tǒng)決定的
實(shí)現(xiàn)Runnable接口創(chuàng)建線程類(lèi)
public Thread() public Thread(Runnable target) public Thread(Runnable target,String name)
- 定義Runnable接口的實(shí)現(xiàn)類(lèi),并重寫(xiě)該接口的run()方法
- 創(chuàng)建Runnable實(shí)現(xiàn)類(lèi)的實(shí)例,并以此作為T(mén)hread的target來(lái)創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象。
public class SecondThread implements Runnable {
public void run(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args) {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
SecondThread st=new SecondThread();
//通過(guò)new Thread(target,name)創(chuàng)建線程
new Thread(st,"新線程1").start();
new Thread(st,"新線程2").start();
}
}
}
}
上面的結(jié)果是兩個(gè)副線程和主線程隨機(jī)切換,但是并沒(méi)有共享資源,因?yàn)樗麄兏緵](méi)有能用來(lái)共享的資源。
start()方法調(diào)用后并不是立即執(zhí)行多線程代碼,而是使得該線程編程可運(yùn)行狀態(tài),什么時(shí)候運(yùn)行是由操作系統(tǒng)決定的
繼承Thread類(lèi)和創(chuàng)建Runnable接口的共享資源詳解
在只有可以用來(lái)共享的資源時(shí)候,也就是同用一個(gè)實(shí)例化對(duì)象。兩個(gè)創(chuàng)建方式在共享資源時(shí)才會(huì)有所區(qū)別,否則它們都不會(huì)共享資源共享資源通常用private static 修飾符來(lái)修飾。
class Thread1 extends Thread{
private int count=5;
private String name;
public Thread1(String name) {
this.name=name;
}
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + "運(yùn)行 count= " + count--);
try {
sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Thread1 mTh1=new Thread1("A");
Thread1 mTh2=new Thread1("B");
mTh1.start();
mTh2.start();
}
}
B運(yùn)行 count= 5 A運(yùn)行 count= 5 B運(yùn)行 count= 4 B運(yùn)行 count= 3 B運(yùn)行 count= 2 B運(yùn)行 count= 1 A運(yùn)行 count= 4 A運(yùn)行 count= 3 A運(yùn)行 count= 2 A運(yùn)行 count= 1
正是因?yàn)橛辛藀rivate int count=5;一句才有了共享資源,但這是繼承Thread類(lèi)的子類(lèi),并不能共享資源
class Thread2 implements Runnable{
private int count=15;
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "運(yùn)行 count= " + count--);
try {
Thread.sleep((int) Math.random() * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Thread2 my = new Thread2();
new Thread(my, "C").start();//同一個(gè)mt,但是在Thread中就不可以,如果用同一個(gè)實(shí)例化對(duì)象mt,就會(huì)出現(xiàn)異常
new Thread(my, "D").start();
new Thread(my, "E").start();
}
}
C運(yùn)行 count= 15 D運(yùn)行 count= 14 E運(yùn)行 count= 13 D運(yùn)行 count= 12 D運(yùn)行 count= 10 D運(yùn)行 count= 9 D運(yùn)行 count= 8 C運(yùn)行 count= 11 E運(yùn)行 count= 12 C運(yùn)行 count= 7 E運(yùn)行 count= 6 C運(yùn)行 count= 5 E運(yùn)行 count= 4 C運(yùn)行 count= 3 E運(yùn)行 count= 2
同樣的正是因?yàn)橛辛藀rivate int count=15這個(gè)共同的實(shí)例化對(duì)象,實(shí)現(xiàn)Runnable的類(lèi)才可以共享資源
那么為什么繼承Thread類(lèi)的子類(lèi)實(shí)現(xiàn)Runable接口的類(lèi)在共享資源時(shí)有區(qū)別呢?
因?yàn)镴ava中只能支持單繼承,單繼承特點(diǎn)意味著只能有一個(gè)子類(lèi)去繼承 而Runnabl接口后可以跟好多類(lèi),便可以進(jìn)行多個(gè)線程共享一個(gè)資源的操作
使用Callable和Future創(chuàng)建線程
Callable怎么看起來(lái)都像Runnable接口的增強(qiáng)版,Callable有一個(gè)call()方法相當(dāng)于Runnable的run()方法,但是功能卻更加強(qiáng)大:
call()方法可以有返回值
call()方法可以聲明拋出異常
Callable接口有泛型限制,Callable接口里的泛型形參類(lèi)型與call()方法的返回值類(lèi)型相同。 而且Callable接口是函數(shù)式接口,因此可使用Lambda表達(dá)式創(chuàng)建Callable對(duì)象 Runnable接口也是函數(shù)式接口,因此也可以使用Lambda表達(dá)式創(chuàng)建Runnable對(duì)象
- 創(chuàng)建Callable接口的實(shí)現(xiàn)類(lèi),并實(shí)現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,再創(chuàng)建Callable實(shí)現(xiàn)類(lèi)的實(shí)例
- 使用FutureTask類(lèi)來(lái)包裝Callable對(duì)象,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法
- 使用FutureTask類(lèi)對(duì)象作為T(mén)hread對(duì)象的target創(chuàng)建并啟動(dòng)新線程
- 調(diào)用FutureTask對(duì)象的get()方法來(lái)獲得子線程結(jié)束后的返回值
public class ThirdThread implements Callable<Integer> {
public Integer call(){
int i=0;
for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
public static void main(String[] args){
ThirdThread tt=new ThirdThread();
FutureTask<Integer> task=new FutureTask<>(tt);
Thread t=new Thread(task,"有返回值的線程");
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
t.start();
}
}
try{
System.out.println("返回值是:"+task.get());
}catch(Exception e){
e.printStackTrace();
}
}
}
使用Lambda表達(dá)式的Callable和Future創(chuàng)建的線程
public class ThirdThread{
public static void main(String[] args){
ThirdThread tt=new ThirdThread();
//先使用Lambda表達(dá)式創(chuàng)建Callable<Integer>對(duì)象
//使用FutureTask封裝Callable對(duì)象
FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{
int i=0;
for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+"的循環(huán)變量i的值:"+i);
}
return i;
});
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"的循環(huán)變量i的值:"+i);
if(i==20){
new Thread(task,"有返回值的線程").start();
}
}
try{
System.out.println("子線程的返回值"+task.get());
}catch(Exception e){
e.printStackTrace();
}
}
}
如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- java 中多線程生產(chǎn)者消費(fèi)者問(wèn)題詳細(xì)介紹
- java多線程編程學(xué)習(xí)(線程間通信)
- Java多線程的用法詳細(xì)介紹
- java多線程學(xué)習(xí)筆記之自定義線程池
- Java基于Socket實(shí)現(xiàn)簡(jiǎn)單的多線程回顯服務(wù)器功能示例
- java 多線程Thread與runnable的區(qū)別
- java多線程學(xué)習(xí)之死鎖的模擬和避免(實(shí)例講解)
- java多線程之火車(chē)售票系統(tǒng)模擬實(shí)例
- Java Socket實(shí)現(xiàn)多線程通信功能示例
- Java多線程用法的實(shí)例詳解
相關(guān)文章
從零開(kāi)始學(xué)springboot整合feign跨服務(wù)調(diào)用的方法
這篇文章主要介紹了從零開(kāi)始學(xué)springboot整合feign跨服務(wù)調(diào)用的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
Java多種方法實(shí)現(xiàn)合并多個(gè)list對(duì)象列表
Java編程中,合并多個(gè)列表對(duì)象可以通過(guò)Stream?API或傳統(tǒng)循環(huán)方式實(shí)現(xiàn),使用Stream?API合并時(shí),利用flatMap方法將嵌套的List展平,再通過(guò)collect方法收集成一個(gè)新的列表,傳統(tǒng)循環(huán)則通過(guò)創(chuàng)建一個(gè)空的ArrayList,并通過(guò)遍歷每個(gè)列表將元素添加進(jìn)去2024-09-09
Java后綴數(shù)組之求sa數(shù)組的實(shí)例代碼
后綴數(shù)組就是一個(gè)字符串所有后綴大小排序后的一個(gè)集合,然后我們根據(jù)后綴數(shù)組的一些性質(zhì)就可以實(shí)現(xiàn)各種需求。這篇文章主要介紹了Java后綴數(shù)組-求sa數(shù)組,需要的朋友可以參考下2018-04-04
Java中List與數(shù)組之間的相互轉(zhuǎn)換
在日常Java學(xué)習(xí)或項(xiàng)目開(kāi)發(fā)中,經(jīng)常會(huì)遇到需要int[]數(shù)組和List列表相互轉(zhuǎn)換的場(chǎng)景,然而往往一時(shí)難以想到有哪些方法,最后可能會(huì)使用暴力逐個(gè)轉(zhuǎn)換法,往往不是我們所滿(mǎn)意的,下面這篇文章主要給大家介紹了關(guān)于Java中List與數(shù)組之間的相互轉(zhuǎn)換,需要的朋友可以參考下2023-05-05
SpringBoot中實(shí)現(xiàn)加載遠(yuǎn)程配置的代碼示例
本文章將通過(guò)結(jié)合consul config來(lái)講解在springboot中如何加載遠(yuǎn)程配置:通過(guò)consul config加載consul server中存儲(chǔ)的配置,需要的朋友可以參考下2023-06-06
詳解Java中Vector和ArrayList的區(qū)別
這篇文章主要為大家詳細(xì)介紹了Java中Vector和ArrayList的區(qū)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10

