Java——多线程实现的三种方式
生活随笔
收集整理的這篇文章主要介紹了
Java——多线程实现的三种方式
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
創(chuàng)建新執(zhí)行線程有三種方法。
第一種方法是將類聲明為 Thread 的子類。該子類應(yīng)重寫 Thread 類的 run 方法。接下來可以分配并啟動(dòng)該子類的實(shí)例。
例如,計(jì)算大于某一規(guī)定值的質(zhì)數(shù)的線程可以寫成:
class PrimeThread extends Thread {long minPrime;PrimeThread(long minPrime) {this.minPrime = minPrime;}public void run() {// compute primes larger than minPrime. . .}}然后,下列代碼會(huì)創(chuàng)建并啟動(dòng)一個(gè)線程:
PrimeThread p = new PrimeThread(143);p.start(); 1,繼承Thread 定義類繼承Thread 重寫run方法 把新線程要做的事寫到run方法中 創(chuàng)建線程對(duì)象 開啟新線程,內(nèi)部會(huì)自動(dòng)執(zhí)行run方法具體的多線程實(shí)現(xiàn)代碼如下:
package com.yy.thread;public class Demo2_Thread { /*** 創(chuàng)建新執(zhí)行線程有兩種方法。* 一種方法是* ①將類聲明為 Thread 的子類。* ②該子類應(yīng)重寫 Thread 類的 run 方法。* ③接下來可以分配并啟動(dòng)該子類的實(shí)例。* */public static void main(String[] args) {//開啟一條線程Mythread mt = new Mythread(); //4,創(chuàng)建線程(Thread類)的子類對(duì)象mt.start(); //5,開啟線程,需要一定的時(shí)間,所以說,JVM會(huì)先執(zhí)行for循環(huán)語句,也就是,會(huì)先輸出bb,之后再輸出aaaaaaa;然后再相互交替輸出//public void start() : 使該線程開始執(zhí)行;Java 虛擬機(jī)調(diào)用該線程的 run 方法。 // mt.run(); //如果這樣調(diào)用,只是調(diào)用了run方法,執(zhí)行run方法里面的for循環(huán),線程還是主線程這一個(gè)線程,不會(huì)出現(xiàn)交替的多線程形式//主線程for (int i = 0; i < 100; i++) { //為了便于觀察多線程的執(zhí)行,在主方法里面進(jìn)行for循環(huán)System.out.println("bb"); //這個(gè)for循環(huán)就是主線程的,兩條線程開啟多線程便于觀察}//兩條線程相互交替進(jìn)行,即多線程實(shí)現(xiàn)}} class Mythread extends Thread{ //1,繼承Threadpublic void run(){ //2,重寫run方法for (int i = 0; i < 100; i++) { //3,將要執(zhí)行的代碼寫到run方法中System.out.println("aaaaaaa"); }} }創(chuàng)建線程的第二種方法是聲明實(shí)現(xiàn) Runnable 接口的類。該類然后實(shí)現(xiàn) run 方法。
然后可以分配該類的實(shí)例,在創(chuàng)建 Thread 時(shí)作為一個(gè)參數(shù)來傳遞并啟動(dòng)。
采用這種風(fēng)格的同一個(gè)例子如下所示:
class PrimeRun implements Runnable {long minPrime;PrimeRun(long minPrime) {this.minPrime = minPrime;}public void run() {// compute primes larger than minPrime. . .}}然后,下列代碼會(huì)創(chuàng)建并啟動(dòng)一個(gè)線程:
每個(gè)線程都有一個(gè)標(biāo)識(shí)名,多個(gè)線程可以同名。如果線程創(chuàng)建時(shí)沒有指定標(biāo)識(shí)名,就會(huì)為其生成一個(gè)新名稱。
具體的多線程實(shí)現(xiàn)代碼如下:
package com.yy.thread;public class Demo3_Thread { /*** 創(chuàng)建線程的另一種方法是* ①聲明實(shí)現(xiàn) Runnable 接口的類。* ②該類然后實(shí)現(xiàn) run 方法。* ③然后可以分配該類的實(shí)例,在創(chuàng)建 Thread 時(shí)作為一個(gè)參數(shù)來傳遞并啟動(dòng)。* * Runnable里面只有一個(gè)run()方法,實(shí)現(xiàn)Runnable只需要重寫run()方法即可* * * 實(shí)現(xiàn)Runnable的原理* 查看源碼:* 1,看Thread類的構(gòu)造函數(shù),傳遞了Runnable接口的引用* 2,通過init()方法找到傳遞的target給成員變量的target賦值* 3,查看run方法,發(fā)現(xiàn)run方法中有判斷,如果target不為null就會(huì)調(diào)用Runnable接口子類對(duì)象的run方法* */public static void main(String[] args) {MyRunnable wsq = new MyRunnable(); //4,創(chuàng)建Runnable的子類對(duì)象 // Runnable target = wsq; //父類引用指向子類對(duì)象,new MyRunnable()這個(gè)是子類對(duì)象也就是wsq Thread yy = new Thread(wsq); //5,將其當(dāng)作參數(shù)傳遞給Thread的構(gòu)造函數(shù); wsq代表Runnable的子類對(duì)象yy.start(); //6,開啟線程; Thread里面才有start()方法// new Thread(wsq).start(); //這種方法與上面的兩行代碼實(shí)現(xiàn)的做用一樣for (int i = 0; i < 100; i++) {System.out.println("你,陪我步入蟬夏,越過城市喧囂,歌聲還在游走,你榴花般的笑容");}} } class MyRunnable implements Runnable { //1,定義一個(gè)類,實(shí)現(xiàn)Runnable方法@Override public void run() { //2,重寫run方法for (int i = 0; i < 100; i++) { //3,將要執(zhí)行的代碼寫到run方法中System.out.println("我真的好想你,在每一個(gè)雨季。"); }} }兩種方法的區(qū)別:
- a.繼承Thread : 由于子類重寫了Thread類的run(),當(dāng)調(diào)用start()時(shí),直接找子類的run()方法
- b.實(shí)現(xiàn)Runnable : 構(gòu)造函數(shù)中傳入了Runnable的引用,成員變量記住了它,start()調(diào)用run()方法時(shí)內(nèi)部判斷成員變量Runnable的引用是否為空,不為空,編譯時(shí)看的是Runnable的run(),運(yùn)行時(shí)執(zhí)行的時(shí)子類的run()方法
繼承Thread(開發(fā)中優(yōu)先考慮)
好處:可以直接使用Thread類中的方法,代碼簡單
弊端:如果已經(jīng)有了父類,就不能有這個(gè)方法,因?yàn)閖ava是單繼承的
實(shí)現(xiàn)Runnable接口(實(shí)際上是對(duì)繼承Thread的補(bǔ)充)
好處:即使自己定義的線程類有了父類也沒關(guān)系,因?yàn)橛辛烁割愐部梢詫?shí)現(xiàn)接口,接口是可以多實(shí)現(xiàn)的,拓展性強(qiáng)
弊端:不能直接使用Thread中的方法,需要先獲取到線程對(duì)象后,才能得到Thread的方法,代碼復(fù)雜
第三種方法是創(chuàng)建類是實(shí)現(xiàn)Callable這個(gè)接口。然后該類重寫 Callable這個(gè)接口里的抽象方法call。
Callable 接口類似于 Runnable,兩者都是為那些其實(shí)例可能被另一個(gè)線程執(zhí)行的類設(shè)計(jì)的。但是 Runnable 不會(huì)返回結(jié)果,并且無法拋出經(jīng)過檢查的異常。
案例:通過實(shí)現(xiàn)Callable這個(gè)接口,來實(shí)現(xiàn)多線程,創(chuàng)建一個(gè)求和類;
具體的多線程實(shí)現(xiàn)代碼如下:
package com.yy.thread;import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;public class Demo6_Callable { /*** 第三種線程創(chuàng)建方式* <T> Future<T> submit(Callable<T> task)* 提交一個(gè)返回值的任務(wù)用于執(zhí)行,返回一個(gè)表示任務(wù)的未決結(jié)果的 Future。* 該 Future 的 get 方法在成功完成時(shí)將會(huì)返回該任務(wù)的結(jié)果。 * Callable 接口類似于 Runnable,兩者都是為那些其實(shí)例可能被另一個(gè)線程執(zhí)行的類設(shè)計(jì)的。但是 Runnable 不會(huì)返回結(jié)果,并且無法拋出經(jīng)過檢查的異常。* * */public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService pool = Executors.newFixedThreadPool(2); //創(chuàng)建線程池,線程池里面可以養(yǎng)兩個(gè)線程Future<Integer> f1 = pool.submit(new MyCallable(100)); //由于下面創(chuàng)建的類中里面有一個(gè)有參構(gòu)造方法,這里得傳一個(gè)參數(shù)Future<Integer> f2 = pool.submit(new MyCallable(50));//submit返回一個(gè)Future,所以說,應(yīng)該用Future去接收//Future可以獲取出來1-100或者是1-50的求和結(jié)果System.out.println(f1.get());System.out.println(f2.get());//V get() throws InterruptedException,ExecutionException如有必要,等待計(jì)算完成,然后獲取其結(jié)果。 pool.shutdown(); //關(guān)閉線程池}} class MyCallable implements Callable<Integer>{ //創(chuàng)建一個(gè)MyCallable類去實(shí)現(xiàn)Callable這個(gè)接口private int num; //設(shè)置一個(gè)成員變量numpublic MyCallable (int num){ //創(chuàng)建一個(gè)有參構(gòu)造方法this.num = num; //num是傳進(jìn)去的數(shù)}@Overridepublic Integer call() throws Exception { //重寫Callable這個(gè)接口里面的抽象方法call;這里的返回值類跟泛型<Integer>是一致的int sum = 0; //實(shí)現(xiàn)求和代碼for (int i = 1; i <= num; i++) {sum += i;}return sum; //返回sum}}總結(jié)
以上是生活随笔為你收集整理的Java——多线程实现的三种方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摩尔庄园猎人小屋在哪
- 下一篇: Java——匿名内部类实现线程的两种方式