以面向接口的设计原则来说,实现多线程编程的方式有两种:实现Runnable接口;实现Callable接口。
实现Runnable接口
我们常见的两种实现多线程编程的方式:实现Runnable接口;继承Thread父类。Thread线程类是Runnable接口的实现类,java类不支持多根继承,类可以实现多个接口,且接口之间支持多根继承,因此此处推荐且只讨论以实现Runnable接口的方式实现多线程编程。
1.定义线程:实现接口Runnable,重写线程的入口方法:run()
public class MyRunnableThread implements Runnable{
public String taskName;
public MyRunnableThread(String taskName) {
super();
this.taskName = taskName;
}
@Override
public void run() {
System.out.println(taskName + " 被执行");
}
}
2.运行线程:线程MyRunnableThread作为构造器参数构建线程运行类:Thread。Thread类的方法:start()启动线程。
public static void main(String[] args) {
int threadSize = 5;
for(int i = 0;i < threadSize;i++) {
// Thread类的方法启动线程,
new Thread(new MyRunnableThread("线程" + i)).start();
}
}
// 执行结果如下,可以看出线程执行的无序性
线程2 被执行
线程0 被执行
线程1 被执行
线程3 被执行
线程4 被执行
实现Callable接口
实现Callable接口和实现Runnable接口的线程不同之处就在于后者的线程有返回值,返回值被Future类封装,通过Future类的方法:get()可以获取线程的返回值。
1.定义线程:实现Callable接口,重写线程的入口方法:call()
public class MyCallableThread implements Callable<Object>{
private String taskName;
public MyCallableThread(String taskName) {
super();
this.taskName = taskName;
}
@Override
public Object call() throws Exception {
System.out.println(taskName + " 被执行");
return taskName;
}
}
2.推荐以线程池ExecutorService的方式运行MyCallableThread
public static void main(String[] args) throws InterruptedException, ExecutionException {
int taskSize = 5;
// 线程池的方式,执行带有返回值的线程(实现接口Callable):MyCallable
// 线程池
ExecutorService executorService = Executors.newFixedThreadPool(taskSize);
// 返回封装结果(Future<Object>)的集合
List<Future<Object>> futures = new ArrayList<>(taskSize);
for(int i = 0;i < taskSize;i++) {
futures.add(executorService.submit(new MyCallableThread("线程 :" + (i + 1))));
}
// 关闭线程池
executorService.shutdown();
Thread.sleep(1000);// 暂停1秒
for (Future<Object> future : futures) {
System.out.println(future.get());
}
}