创建一个线程可以有3中方法:
1.继承Thread类 2.实现Runnable接口 3.实现Callable接口 第1种和第2种不会有返回值,第3种可以有返回值.
class NewThread1 extends Thread{
//重写run方法
public void run(){
System.out.println("this is a new thread1");
}
}
class NewThread2 implements Runnable{
private static int taskCount = 0;
private final int taskNo = taskCount++;
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("before:newthread2 No is"+taskNo);
Thread.yield();
System.out.println("after:newthread2 No is"+taskNo);
}
}
class NewThread3 implements Callable<String>{
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
System.out.println("this is a new thread3");
return "thread3 result";
}
}
根据不同的线程任务创建方法的不同,启动线程的方法也有差别主要分为2种:Thread类的start()方法,使用java.util.concurrent包中的执行器Executor。
public static void main(String[] args) {
// TODO Auto-generated method stub
//使用线程的start方法,适合实现Runable或者是继承Thread的任务
NewThread1 newThread1 = new NewThread1();
newThread1.start();
Thread thread2 = new Thread(new NewThread2());
thread2.start();
//使用执行器Executor,适合实现了Runable的任务
ExecutorService exec = Executors.newCachedThreadPool();
// ExecutorService exec = Executors.newFixedThreadPool(5);
// ExecutorService exec = Executors.newSingleThreadExecutor();
for(int i = 0;i<5;i++){
exec.execute(new NewThread2());
}
//使用ExecutorService.submit()方法启动实现callable的任务
Future<String> fs;
fs = exec.submit(new NewThread3());
try {
System.out.println("newThread3 out:"+fs.get());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
exec.shutdown();
}
利用start()方法,对于继承Thread和实现Runnable的任务都适合,注:如果是调用run(),就是单纯的函数调用,是在main方法的线程中执行run方法。
实现Runnable接口的任务也可以利用执行器executor来启动线程。常用的执行器有3类:CachedThreadPool(),FixedThreadPool(int), SingleThreadExecutor().3种都可以来启动多个线程,主要的差别是:CachedhThreadPool为每一个任务创建一个线程,来了任务才分配线程资源,FixedThreadPool一次性的执行固定的线程资源分配,代价高,但是节省时间。一般情况下建议使用CachedThreadPool。SingleThreadExecutor类似参数为1的FixedThreadPool,另一个区别是向SingleThreadExecutor提交多个任务时,这些任务将会排队,一个任务完全执行完后才会下一个任务,其他2个执行器不会,当有多个任务提交形成多个线程时,任务结果是乱序的。
实现Callable接口的任务只能用submit来启动线程,返回的是一个Future<V>类型的结果,带有泛型V。利用方法get()可以取出结果的值。
CachedThreadPool执行结果图:
使用CachedThreadPool运行newThrad2. 5个线程是乱序的。并且每次执行的结果都会不会一样。
SingleThreadExecutor执行结果图:
使用SingleHhreadExecutor执行newthread2时。即使有yield()使该线程放弃CPU,但是提交的5个任务是依次完成。