command对象提供的3个execute方法是_并发面试题:java中有几种方法可以实现一个线程?...
創(chuàng)建并啟動線程的6種方式
- 繼承Thread類創(chuàng)建線程
- 實現(xiàn)Runnable接口創(chuàng)建線程
- 使用Callable和FutureTask創(chuàng)建線程
- 使用線程池,例如用Executor框架
- Spring實現(xiàn)多線程(底層是線程池)
- 定時器Timer (底層封裝了一個TimerThread對象)
1、繼承Thread類創(chuàng)建線程
1.1繼承Thread類方式創(chuàng)建線程的實現(xiàn)步驟:
步驟:
1) 定義一個類A繼承于java.lang.Thread類
2)在A類中覆蓋Thread類中的run方法
3)我們在run方法中編寫需要執(zhí)行的操作---->run方法里的,線程執(zhí)行體
4)在main方法(線程)中,創(chuàng)建線程對象,并啟動線程
- 創(chuàng)建線程類對象: A類 a = new A類();
- 調(diào)用線程對象的start方法: a.start();//啟動一個線程
注意:千萬不要調(diào)用run方法,如果調(diào)用run方法好比是對象調(diào)用方法,依然還是只有一個線程,并沒有開啟新的線程。
1.2需求:使用兩個線程實現(xiàn)邊聽歌邊打游戲
實現(xiàn)代碼:
//音樂線程 public class MusicThread { public static void main(String[] args) { //創(chuàng)建游戲線程對象 GameThread game = new GameThread(); //啟動游戲線程 game.start(); while(true){ System.out.println(Thread.currentThread().getName()+"聽音樂!"); } } } //游戲線程 class GameThread extends Thread{ @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName()+"打游戲!"); } } }注意:有的小伙伴可能覺得音樂線程沒有啟動,在這里其實音樂線程已經(jīng)啟動起來了,而啟動音樂線程的對象就是我們的JVM,此處main方法其實啟動的時候會創(chuàng)建一個主線程去執(zhí)行main方法,所以我在這里使用主線程作為了我的音樂線程。
2、實現(xiàn)Runnable接口創(chuàng)建線程
2.1實現(xiàn)Runnable接口方式創(chuàng)建線程的實現(xiàn)步驟:
1)定義一個類A實現(xiàn)于java.lang.Runnable接口,注意A類不是線程類。 2)在A類中覆蓋Runnable接口中的run方法。 3) 我們在run方法中編寫需要執(zhí)行的操作---->run方法里的,線程執(zhí)行體。 4)在main方法(線程)中,創(chuàng)建線程對象,并啟動線程。
- 創(chuàng)建線程類對象: Thread t = new Thread(new A());
- 調(diào)用線程對象的start方法: t.start();
2.2需求:使用兩個線程實現(xiàn)邊聽歌邊打游戲
實現(xiàn)代碼:
//音樂線程 public class MusicThread { public static void main(String[] args) { //創(chuàng)建游戲線程對象 Thread game = new Thread(new Game()); //啟動游戲線程 game.start(); while(true){ System.out.println(Thread.currentThread().getName()+"聽音樂!"); } } }//游戲 class Game implements Runnable{ @Override public void run() { while (true) { System.out.println(Thread.currentThread().getName()+"打游戲!"); } } }2.3 繼承方式和實現(xiàn)方式的區(qū)別
1)繼承方式是一個類繼承了Thread后成為線程類的子類,實現(xiàn)方式是一個類實現(xiàn)Runnable接口,但是這個類不是線程類,因為該類沒有start等方法。
2)啟動的時候繼承方式直接調(diào)用自己的start方法,實現(xiàn)方式是借助了Thread中的start方法啟動的,自身沒有start方法。
3)繼承方式調(diào)用的run方法是通過方法覆蓋,通過繼承方式實現(xiàn)的,運行的時候先找子類,沒有最后才運行父類的run方法。實現(xiàn)方式是執(zhí)行Thread的run方法,而Thread中的run方法調(diào)用了實現(xiàn)類中的run方法,使用過組合關(guān)系的方法調(diào)用實現(xiàn)的。
3、實現(xiàn) Callable 接口
3.1使用Callable和FutureTask創(chuàng)建線程的實現(xiàn)步驟:
1)定義一個Callable接口的實現(xiàn)類
2)創(chuàng)建Callable實現(xiàn)類對象傳遞給FutureTask構(gòu)造器
3)將FutureTask對象傳遞給Thread構(gòu)造器
4)Thread對象調(diào)用start方法啟動線程
5)通過FutureTask對象的get方法獲取線程運行的結(jié)果
注意: Future就是對于具體的Runnable或者Callable任務(wù)的執(zhí)行結(jié)果進行取消、查詢是否完成、獲取結(jié)果。必要時可以通過get方法獲取執(zhí)行結(jié)果,該方法會阻塞直到任務(wù)返回結(jié)果。
使用場景:使用多線程計算結(jié)果并返回該結(jié)果。
3.2需求:使用2個線程異步計算1-1000,000內(nèi)之和
實現(xiàn)代碼:
public class CallableDemo { public static void main(String[] args) throws Exception { //1.創(chuàng)建并啟動線程 Callable<Integer> call1 = new CallableImpl(0, 50000); Callable<Integer> call2 = new CallableImpl(50001, 100000);FutureTask<Integer> f1 = new FutureTask<>(call1); FutureTask<Integer> f2 = new FutureTask<>(call2);new Thread(f1).start(); new Thread(f2).start(); //2.獲取每一個線程的結(jié)果 int ret1 = f1.get(); int ret2 = f2.get(); int ret= ret1+ret2; System.out.println(ret); } } class CallableImpl implements Callable<Integer>{private int min; private int max;public CallableImpl(int min, int max) { this.min = min; this.max = max; }@Override public Integer call() throws Exception { int sum = 0; for (int i = min; i <= max; i++) { sum+=i; } return sum; } }3.3Callable和Runnable的區(qū)別如下:
Callable定義的方法是call,而Runnable定義的方法是run。
Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
Callable的call方法可拋出異常,而Runnable的run方法不能拋出異常。
注意:
FutureTask為Runnable的實現(xiàn)類
FutureTask可以視為一個閉鎖(門閂),因為只有當線程運行完才會出現(xiàn)結(jié)果。
4、使用線程池
線程池,顧名思義就是一個池子里面放了很多的線程,我們用就將線程從里面拿出來,使用完畢就放回去池子中。設(shè)計和數(shù)據(jù)庫連接池相似,存在靜態(tài)工廠方法用于創(chuàng)建各種線程池。
操作步驟:
1)使用Executors工具類中的靜態(tài)工廠方法用于創(chuàng)建線程池 newFixedThreadPool:創(chuàng)建可重用且固定線程數(shù)的線程池, newScheduledThreadPool:創(chuàng)建一個可延遲執(zhí)行或定期執(zhí)行的線程池 newCachedThreadPool:創(chuàng)建可緩存的線程池
2)使用execute方法啟動線程
3)使用shutdown方法等待提交的任務(wù)執(zhí)行完成并后關(guān)閉線程。
代碼演示如下:
public class Demo4 {public static void main(String[] args) {Executor executor = Executors.newFixedThreadPool(5);executor.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}});((ExecutorService) executor).shutdown();} }5、Spring實現(xiàn)多線程
在Spring3之后,Spring引入了對多線程的支持,如果你使用的版本在3.1以前,應(yīng)該還是需要通過傳統(tǒng)的方式來實現(xiàn)多線程的。從Spring3同時也是新增了Java的配置方式,而且Java配置方式也逐漸成為主流的Spring的配置方式。
代碼演示如下:
導(dǎo)入的包:
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.1.0.RELEASE</version></dependency> </dependencies>配置類:
@Configuration @ComponentScan("cn.wolfcode") @EnableAsync //允許使用異步任務(wù) public class SpringConfig {}服務(wù)類:
@Service public class SpringService {@Async // 這里進行標注為異步任務(wù),在執(zhí)行此方法的時候,會單獨開啟線程來執(zhí)行public void dowork1() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}}@Asyncpublic void dowork2() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}} }測試類:
public class SpringThreadDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);SpringService bean = context.getBean(SpringService.class);bean.dowork1();bean.dowork2();} }注意:此時會出現(xiàn)一個DEBUG信息
在這里DEBUG信息不是什么錯誤,不會影響代碼的正常運行,其實可以不用管的,但是為什么出現(xiàn)這個問題呢?
Spring的定時任務(wù)調(diào)度器會通過BeanFactory.getBean的方法來嘗試獲取一個注冊過的TaskExecutor對象來做任務(wù)調(diào)度,獲取不到TaskExecutor對象再嘗試找ScheduledExecutorService 對象,都找不到就報DEBUG信息。報錯之后就找自己本身默認的scheduler定時器對象,這個舉動其實是做一個提醒作用,所以如果沒有強迫癥可以不用管它。
解決Spring使用多線程的報錯信息
強迫癥患者想要解決怎么辦,三種方式:
- 在log4j文件中加入log4j.logger.org.springframework.scheduling = INFO(治標不治本)
- 在本配置文件或者配置類中設(shè)置一個bean
- 配置類實現(xiàn)AsyncConfigurer接口并覆蓋其getAsyncExecutor方法
6 定時器
嚴格來說定時器(Timer)不是線程,他只是調(diào)度線程的一種工具,它里面封裝了一個線程,所以我們可以使用定時器來使用線程。
操作步驟:
1)創(chuàng)建Timer 對象
2)調(diào)用schedule方法
3)傳入TimerTask子類對象
代碼演示如下:
Timer timer = new Timer(); timer.schedule(new TimerTask() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "-->" + i);}} }, 100, 100);?文源網(wǎng)絡(luò),僅供學(xué)習(xí)之用,如有侵權(quán),聯(lián)系刪除。
我整理了一套學(xué)習(xí)資料,涵蓋Java虛擬機、spring框架、Java線程、數(shù)據(jù)結(jié)構(gòu)、設(shè)計模式等等,免費提供給熱愛Java的同學(xué)! 戳我主頁查看獲取方式。
總結(jié)
以上是生活随笔為你收集整理的command对象提供的3个execute方法是_并发面试题:java中有几种方法可以实现一个线程?...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (四)ElasticSearch之数据
- 下一篇: .net多层结构 sql注入