详解三种java实现多线程的方式
java中实现多线程的方法有两种:继承Thread类和实现runnable接口。
1.继承Thread类,重写父类run()方法
publicclassthread1extendsThread{ publicvoidrun(){ for(inti=0;i<10000;i++){ System.out.println("我是线程"+this.getId()); } } publicstaticvoidmain(String[]args){ thread1th1=newthread1(); thread1th2=newthread1(); th1.run(); th2.run(); } }
run()方法只是普通的方法,是顺序执行的,即th1.run()执行完成后才执行th2.run(),这样写只用一个主线程。多线程就失去了意义,所以应该用start()方法来启动线程,start()方法会自动调用run()方法。上述代码改为:
publicclassthread1extendsThread{ publicvoidrun(){ for(inti=0;i<10000;i++){ System.out.println("我是线程"+this.getId()); } } publicstaticvoidmain(String[]args){ thread1th1=newthread1(); thread1th2=newthread1(); th1.start(); th2.start(); } }
通过start()方法启动一个新的线程。这样不管th1.start()调用的run()方法是否执行完,都继续执行th2.start()如果下面有别的代码也同样不需要等待th2.start()执行完成,而继续执行。(输出的线程id是无规则交替输出的)
2.实现runnable接口
publicclassthread2implementsRunnable{ publicStringThreadName; publicthread2(StringtName){ ThreadName=tName; } publicvoidrun(){ for(inti=0;i<10000;i++){ System.out.println(ThreadName); } } publicstaticvoidmain(String[]args){ thread2th1=newthread2("线程A"); thread2th2=newthread2("线程B"); th1.run(); th2.run(); } }
和Thread的run方法一样Runnable的run只是普通方法,在main方法中th2.run()必须等待th1.run()执行完成后才能执行,程序只用一个线程。要多线程的目的,也要通过Thread的start()方法(注:runnable是没有start方法)。上述代码修改为:
publicclassthread2implementsRunnable{ publicStringThreadName; publicthread2(StringtName){ ThreadName=tName; } publicvoidrun(){ for(inti=0;i<10000;i++){ System.out.println(ThreadName); } } publicstaticvoidmain(String[]args){ thread2th1=newthread2("线程A"); thread2th2=newthread2("Thread-B"); Threadmyth1=newThread(th1); Threadmyth2=newThread(th2); myth1.start(); myth2.start(); } }
3.使用ExecutorService、Callable、Future实现有返回结果的多线程(JDK5.0以后)
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题可以直接使用。代码如下:
importjava.util.concurrent.*; importjava.util.Date; importjava.util.List; importjava.util.ArrayList; /** *有返回值的线程 */ @SuppressWarnings("unchecked") publicclassTest{ publicstaticvoidmain(String[]args)throwsExecutionException, InterruptedException{ System.out.println("----程序开始运行----"); Datedate1=newDate(); inttaskSize=5; //创建一个线程池 ExecutorServicepool=Executors.newFixedThreadPool(taskSize); //创建多个有返回值的任务 List<Future>list=newArrayList<Future>(); for(inti=0;i<taskSize;i++){ Callablec=newMyCallable(i+""); //执行任务并获取Future对象 Futuref=pool.submit(c); //System.out.println(">>>"+f.get().toString()); list.add(f); } //关闭线程池 pool.shutdown(); //获取所有并发任务的运行结果 for(Futuref:list){ //从Future对象上获取任务的返回值,并输出到控制台 System.out.println(">>>"+f.get().toString()); } Datedate2=newDate(); System.out.println("----程序结束运行----,程序运行时间【" +(date2.getTime()-date1.getTime())+"毫秒】"); } } classMyCallableimplementsCallable<Object>{ privateStringtaskNum; MyCallable(StringtaskNum){ this.taskNum=taskNum; } publicObjectcall()throwsException{ System.out.println(">>>"+taskNum+"任务启动"); DatedateTmp1=newDate(); Thread.sleep(1000); DatedateTmp2=newDate(); longtime=dateTmp2.getTime()-dateTmp1.getTime(); System.out.println(">>>"+taskNum+"任务终止"); returntaskNum+"任务返回运行结果,当前任务时间【"+time+"毫秒】"; } }
代码说明:
上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
publicstaticExecutorServicenewFixedThreadPool(intnThreads)
创建固定数目线程的线程池。
publicstaticExecutorServicenewCachedThreadPool()
创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有60秒钟未被使用的线程。
publicstaticExecutorServicenewSingleThreadExecutor()
创建一个单线程化的Executor。
publicstaticScheduledExecutorServicenewScheduledThreadPool(intcorePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
总结:实现java多线程的2种方式,runable是接口,thread是类,runnable只提供一个run方法,建议使用runable实现java多线程,不管如何,最终都需要通过thread.start()来使线程处于可运行状态。第三种方法是听群里的兄弟们介绍的,所以就百度补上了。
以上就是本文的全部内容,希望对大家的学习有所帮助。