1. 继承Thread类
继承Thead类,重写run()方法。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
2. 实现Runnable接口
实现Runnable接口,重写run()方法。
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
3. 实现Callable接口(JDK1.5)
实现Callable接口,重写call()方法,需要与FutureTask结合使用。
与上面两种创建方式最大的区别在于,实现Callable接口方式可以有返回值,能够抛出异常。
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
return Thread.currentThread().getName();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask futureTask = new FutureTask(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get()); // 获取结果
}
}
4. ThreadPoolExecutor
Jdk中提供了一个Executors的线程池工具类,其中最主要有三种创建普通线程池的方法。
// 固定大小的线程池(使用于负载比较重的服务器)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
// 单线程池(需要保证顺序执行各个任务的场景)
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// 缓存线程池(适用于提交短期的异步小程序,以及负载较轻的服务器)
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
注:但是在实际工作中,强制禁止使用Executors类来创建线程池,需要通过ThreadPoolExecutor的方式,原因参考Alibaba Java开发手册。
5. Fork/Join
Fork/Join是JDK 1.7加入的新的线程池实现,它提现的是一种分治思想,适用于能够进行任务拆分的 cpu 密集型运算。
所谓的任务拆分,是将一个大任务拆分为算法上相同的小任务,直至不能拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列、都可以用分治思想进行求解。
Fork/Join在分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升了运算效率。
Fork/Join默认会创建与 cpu 核心数大小相同的线程池。
提交给Fork/Join线程池的任务需要继承 RecursiveTask(有返回值)或 RecursiveAction(没有返回值),例如下面定义了一个1~n之间的整数求和的任务。
public class ForkJoinTest {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool(4);
System.out.println(forkJoinPool.invoke(new Task(5)));
}
}
class Task extends RecursiveTask<Integer> {
private int n;
public Task(int n) {
this.n = n;
}
@Override
protected Integer compute() {
// 终止条件
if (n == 1) {
return 1;
}
Task task = new Task(n - 1);
task.fork(); // 让一个线程去执行此任务
return n + task.join(); // 获取任务结果
}
}