java 创建线程有三种方式:
(一) 实现Runnable接口
优点:(1) 创建线程的同时可以继承其他的类,从而可以扩展类的功能。
(2) 同一个实现Runnable接口的实例可以作为多个Thread的target,这样可以实现资源的共享。
缺点:相对于继承Thread类,实现Runnable接口代码要繁琐一些
代码实例如下:
public class ImplementsRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" ThreadId: "+ Thread.currentThread().getId());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// 输出主线程的相关信息
System.out.println(Thread.currentThread().getName()+" ThreadId: "+ Thread.currentThread().getId());
// 创建thread1线程
ImplementsRunnable runnableTarget = new ImplementsRunnable();
Thread thread1 = new Thread(runnableTarget,"ThreadName1");
thread1.start();
// 以匿名内部类的形式创建target 创建thread2线程
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+" ThreadId: "+ Thread.currentThread().getId());
}
},"ThreadName2").start();
}
}
输出结果:main ThreadId: 1
ThreadName1 ThreadId: 9
ThreadName2 ThreadId: 10
(二) 继承Thread 类,重载Thread类的run()方法。事实上Thread类也是实现了Runnable接口。
优点:代码相对其他两种方式更简洁
缺点:由于java的继承机制是单一继承,继承Thread类就不能继承其他的类。
代码实例:
public class ExtendsThread extends Thread{
public ExtendsThread(String threadName) {
super(threadName);
}
public void run() {
System.out.println("ThreadName: " + getName());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// 输出主线程的相关信息
System.out.println(Thread.currentThread().getName()+" ThreadId: "+ Thread.currentThread().getId());
// 创建子线程
ExtendsThread et = new ExtendsThread("childThread");
et.start();
}
}
(三) 实现Callable<V>接口 并实现接口的唯一方法call()
有些场景会希望得到线程的计算结果,这时可以实现Callable<V> 接口。Callable<V>接口和Runnable接口都是封装了一个异步任务,不同的是
Callable<V>接口具有返回值。同时Call<V>接口还是一个参数化的类型,这个参数就是线程的返回参数类型,比如线程若返回整型则Callable<Integer>
,若返回字符类型则为Callable<Object>。
通过实现Callable<V>接口创建线程,需要用到一个包装器FutureTask<V>,这个包装器同时实现了Runnable和Future<V>接口,它可以将Callable<V>
对象转换为Runnable和Future。
public interface Callable<V> {
V call() throws Exception;
}
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
public class FutureTask<V> implements RunnableFuture<V> {
......
}
代码实例:
public class ImplemetsCallable implements Callable<Integer>{
// 实现call()方法
public Integer call() {
return 35;
}
public static void main(String [] args) throws
InterruptedException, ExecutionException, TimeoutException {
ImplemetsCallable ic = new ImplemetsCallable();
// 创建包装器 FutureTask 同时实现了Runnable和Future接口 可以将Callable 转换成Future和Runnable
FutureTask<Integer> task = new FutureTask<Integer>(ic);
Thread t = new Thread(task);
t.start();
// 调用FutureTask的get() 方法 获取线程的计算结果
// 如果线程没有计算完结果 则get()方法会阻塞 直到线程计算完结果返回
System.out.println(task.get());
// get(long timeout, TimeUnit unit)方法在指定时间内获取线程计算结果,超时则抛出 TimeoutException异常
// 如果运行计算结果的线程被中断则get()和get(long timeout, TimeUnit unit)方法都将抛出InterruptedException异常
System.out.println(task.get(10000, TimeUnit.MILLISECONDS));
}
}
以下代码是通过使用线程池的方式创建线程:
public class TestCallable {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("程序开始执行");
List<Future> list = new ArrayList<Future>();
int taskSize = 5;
// 创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
for (int i = 0; i<taskSize; i++) {
MyCallable mc = new MyCallable("i "+i);
Future f = pool.submit(mc);
list.add(f);
}
for (Future f : list) {
try {
System.out.println(f.get().toString());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class MyCallable implements Callable<Object> {
private String name;
public MyCallable(String name) {
this.name = name;
}
public Object call() {
System.out.println("任务开始执行>>>>");
long beginTime = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
long durTime = endTime - beginTime;
System.out.println("任务执行完毕>>>>");
return name + "任务执行完毕>>>> 总耗时: "+ durTime;
}
}