要领一:继续类,掩盖要领run()
我们在竖立的Thread类的子类中重写run() ,到场线程所要实行的代码即可。
下面是一个例子:
public class MyThread extends Thread { int count= 1, number; public MyThread(int num) { number = num; System.out.println ("竖立线程 " + number); } public void run() { while(true) { System.out.println ("线程 " + number + ":计数 " + count); if(++count== 6) return; } } public static void main(String args[]) { for(int i = 0;i 〈 5; i++) new MyThread(i+1).start(); } }
这类要领简单明了,相符人人的习气,然则,它也有一个很大的瑕玷,那就是假如我们的类已从一个类继续(如小顺序必需继续自 Applet 类),则没法再继续 Thread 类,这时候假如我们又不想竖立一个新的类,应当怎么办呢?
我们无妨来探究一种新的要领:我们不竖立Thread类的子类,而是直接运用它,那末我们只能将我们的要领作为参数通报给 Thread 类的实例,有点相似回调函数。然则 Java 没有指针,我们只能通报一个包括这个要领的类的实例。
那末怎样限定这个类必需包括这一要领呢?当然是运用接口!(虽然抽象类也可满足,然则须要继续,而我们之所以要采纳这类新要领,不就是为了防止继续带来的限定吗?)
Java 供应了接口 java.lang.Runnable 来支撑这类要领。
要领二:完成 Runnable 接口
Runnable接口只要一个要领run(),我们声明本身的类完成Runnable接口并供应这一要领,将我们的线程代码写入个中,就完成了这一部份的使命。然则Runnable接口并没有任何对线程的支撑,我们还必需竖立Thread类的实例,这一点经由过程Thread类的组织函数 public Thread(Runnable target);来完成。下面是一个例子:
public class MyThread implements Runnable { int count= 1, number; public MyThread(int num) { number = num; System.out.println("竖立线程 " + number); } public void run() { while(true) { System.out.println ("线程 " + number + ":计数 " + count); if(++count== 6) return; } } public static void main(String args[]) { for(int i = 0; i 〈 5;i++) new Thread(new MyThread(i+1)).start(); } }
严格地说,竖立Thread子类的实例也是可行的,然则必需注重的是,该子类必需没有掩盖 Thread类的 run 要领,不然该线程实行的将是子类的 run 要领,而不是我们用以完成Runnable 接口的类的 run 要领,对此人人无妨实验一下。
运用 Runnable 接口来完成多线程使得我们可以在一个类中包涵一切的代码,有利于封装,它的瑕玷在于,我们只能运用一套代码,若想竖立多个线程并使各个线程实行差别的代码,则仍必需分外竖立类,假如如许的话,在大多半情况下或许还不如直接用多个类离别继续 Thread 来得紧凑。
要领三、运用ExecutorService、Callable、Future完成有返回效果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功用类。想要细致相识Executor框架的可以接见http://www.javaeye.com/topic/366591 ,这里面临该框架做了很细致的诠释。返回效果的线程是在JDK1.5中引入的新特性,确切很有用,有了这类特性我就不须要再为了获得返回值而大费周折了,而且即使完成了也能够漏洞百出。
可返回值的使命必需完成Callable接口,相似的,无返回值的使命必需Runnable接口。实行Callable使命后,可以猎取一个Future的对象,在该对象上挪用get就可以猎取到Callable使命返回的Object了,再连系线程池接口ExecutorService就可以完成传说中有返回效果的多线程了。下面供应了一个完全的有返回效果的多线程测试例子,在JDK1.5下考证过没问题可以直接运用。代码以下:
import java.util.concurrent.*; import java.util.Date; import java.util.List; import java.util.ArrayList; @SuppressWarnings("unchecked") public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("----顺序最先运转----"); Date date1 = new Date(); int taskSize = 5; // 竖立一个线程池 ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 竖立多个有返回值的使命 List list = new ArrayList(); for (int i = 0; i < taskSize; i++) { Callable c = new MyCallable(i + " "); // 实行使命并猎取Future对象 Future f = pool.submit(c); // System.out.println(">>>" + f.get().toString()); list.add(f); } // 封闭线程池 pool.shutdown(); // 猎取一切并发使命的运转效果 for (Future f : list) { // 从Future对象上猎取使命的返回值,并输出到控制台 System.out.println(">>>" + f.get().toString()); } Date date2 = new Date(); System.out.println("----顺序完毕运转----,顺序运转时候【" + (date2.getTime() - date1.getTime()) + "毫秒】"); } } class MyCallable implements Callable { private String taskNum; MyCallable(String taskNum) { this.taskNum = taskNum; } public Object call() throws Exception { System.out.println(">>>" + taskNum + "使命启动"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "使命停止"); return taskNum + "使命返回运转效果,当前使命时候【" + time + "毫秒】"; } }
代码申明:
上述代码中Executors类,供应了一系列工场要领用于创先线程池,返回的线程池都完成了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
竖立牢固数量线程的线程池。
public static ExecutorService newCachedThreadPool()
竖立一个可缓存的线程池,挪用execute 将重用之前组织的线程(假如线程可用)。假如现有线程没有可用的,则竖立一个新线程并添加到池中。停止并从缓存中移除那些已有 60 秒钟未被运用的线程。
public static ExecutorService newSingleThreadExecutor()
竖立一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
竖立一个支撑定时及周期性的使命实行的线程池,多半情况下可用来替换Timer类。
ExecutoreService供应了submit()要领,通报一个Callable,或Runnable,返回Future。假如Executor背景线程池还没有完成Callable的盘算,这挪用返回Future对象的get()要领,会壅塞直到盘算完成。
综上所述,以上要领各有所长,人人可以灵活运用。
以上就是Java中怎样完成多线程?(代码示例)的细致内容,更多请关注ki4网别的相干文章!