当前位置: 首页 > 科技观察

Java线程系列8种创建线程方法

时间:2023-03-12 20:05:05 科技观察

简介创建线程是多线程编程中最基本的操作。童哥总结了一下。创建线程大概有8种方法,你知道吗?继承Thread类,重写run()方法;newCreatingThread01().start();newCreatingThread01().start();newCreatingThread01().start();}}继承Thread类,重写run()方法。这种方法的缺点是一个类只能继承一个父类,如果类本身已经继承了其他类,则不能使用这种方法。实现Runnable接口();newThread(newCreatingThread02()).start();newThread(newCreatingThread02()).start();newThread(newCreatingThread02()).start();}}实现Runnable接口。这种方法的优点是一个类可以实现多个接口,不影响其继承体系。匿名内部类publicclassCreatingThread03{publicstaticvoidmain(String[]args){//Thread匿名类,覆盖Thread的run()方法newThread(){@Overridepublicvoidrun(){System.out.println(getName()+"isrunning");}}.start();//Runnable匿名类,实现其run()方法newThread(newRunnable(){@Overridepublicvoidrun(){System.out.println(Thread.currentThread().getName()+"isrunning").}).start();}}使用匿名类的方法一是重写Thread的run()方法,二是传入Runnable的匿名类,三是使用lambda方法。现在普遍使用第三种方式(java8+),简单快捷。实现Callabe接口publicclassCreatingThread04implementsCallable{@OverridepublicLongcall()throwsException{Thread.sleep(2000);System.out.println(Thread.currentThread().getId()+"isrunning");returnThread.currentThread().getId();}publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{FutureTasktask=newFutureTask<>(newCreatingThread04());newThread(task).start();System.out.println("等待任务完成");Longresult=task.get();System.out.println("任务结果:"+result);}}实现Callabe接口,可以获取线程执行的结果,FutureTask实际实现了Runnable接口.定时器(java.util.Timer)publicclassCreatingThread05{publicstaticvoidmain(String[]args){Timertimer=newTimer();//执行timer.schedule(newTimerTask(){@Overridepublicvoidrun(){System.out.println(Thread.currentThread().getName()+"isrunning");}},0,1000);}}定时器java.util.Timer可以用来快速实现定时任务。TimerTask实际上实现了Runnable接口。线程池publicclassCreatingThread06{publicstaticvoidmain(String[]args){ExecutorServicethreadPool=Executors.newFixedThreadPool(5);for(inti=0;i<100;i++){threadPool.execute(()->System.out.println(Thread.currentThread().getName()+"isrunning"));}}}使用线程池重用线程,节省系统资源。并行计算(Java8+)publicclassCreatingThread07{publicstaticvoidmain(String[]args){Listlist=Arrays.asList(1,2,3,4,5);//串口,打印结果为12345list.stream()。forEach(System.out::print);System.out.println();//并行,随机打印结果,如35214list.parallelStream().forEach(System.out::print);}}使用并行计算,可以提高程序运行效率,多线程并行执行。spring的异步方法首先,springboot的启动类被@EnableAsync注解(@EnableAsync是spring支持的,这里举一个方便使用springboot的例子)。@SpringBootApplication@EnableAsyncpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Application.class,args);}}其次,该方法使用@Async注解。@ServicepublicclassCreatingThread08Service{@Asyncpublicvoidcall(){System.out.println(Thread.currentThread().getName()+"isrunning");}}然后,测试用例和使用一般的Service方法完全一样。@RunWith(SpringRunner.class)@SpringBootTest(classes=Application.class)publicclassCreatingThread08Test{@AutowiredprivateCreatingThread08ServicecreatingThread08Service;@Testpublicvoidtest(){creatingThread08Service.call();creatingThread08Service.call();creatingThread08Service.call();Service.call08}}这个运行结果如下:task-3isrunningtask-2isrunningtask-1isrunningtask-4isrunning可以看到每次执行该方法使用的线程都不一样。使用Spring异步方法的方式可以说是相当方便了。适用于一些适合异步调用的与前后逻辑无关的方法,比如发送短信的功能。总结(1)继承Thread类,重写run()方法;(2)实现Runnable接口;(3)匿名内部类;(4)实现Callabe接口;(5)定时器(java.util.Timer);(6)线程池;(7)并行计算(Java8+);(8)Spring异步方法;上面介绍了很多创建线程的方法,其实本质上有两种,一种是继承Thread类并重写它的run()方法,一种是实现了Runnable接口的run()方法,那么什么是他们之间的联系?请看下面的例子,在继承Thread并实现Runnable接口时,应该输出什么?publicclassCreatingThread09{publicstaticvoidmain(String[]args){newThread(()->{System.out.println("Runnable:"+Thread.currentThread().getName());}){@Overridepublicvoidrun(){System.out.println("Thread:"+getName());}}.start();}}说到这里,还要看Thread类的源码:publicclassThreadimplementsRunnable{//Thread维护了一个Runnable实例privateRunnabletarget;publicThread(){init(null,null,"Thread-"+nextThreadNum(),0);}publicThread(Runnabletarget){init(null,target,"Thread-"+nextThreadNum(),0);}privatevoidinit(ThreadGroupg,Runnabletarget,Stringname,longstackSize,AccessControlContextacc,booleaninheritThreadLocals){//...//构造方法传入的Runnable会赋值给targetthis.target=target;//...}@Overridepublicvoidrun(){//Thread默认的run()方法,如果target不为空,就会执行target的run()方法if(target!=null){target.run();}}}看这里是不是豁然开朗?由于上面的例子继承了Thread,同时实现了Runnable接口,根据源码来看,其实相当于重写了Thread的run()方法。在Thread的run()方法中,其实和target没有任何关系。因此,上面例子的输出结果是Thread:Thread-0,只输出重写Thread的run()方法中的内容。