继承 Thread 类
继承线程类,然后重写 run 方法,调用线程 start 方法后, 等待 JVM 为当前线程分配到 CPU 时间片会调用 run 方法执行。
class Thread1 extends Thread { @Override public void run() { //dosomething() System.out.println("Thread1"); } }
实现 Runnable 接口
实现 Runnable 接口,重写 run 方法,执行线程需要丢入 Runnable 接口实现类,调用 Thread 对象的 start 方法执行。
// 定义线程 class Runner1 implements Runnable { @Override public void run() { //dosomething() System.out.println("Runner1"); } } // 线程执行 new Thread thread = new Thread(new Runner1()); thrad.start();
创建 Callable 接口的实现类
Callable: 返回结果并且可能抛出异常的任务。 优点:
- 可以获得任务执行返回值;
- 通过与 Future 的结合,可以实现利用 Future 来跟踪异步计算的结果。
class Callable1 implements Callable { @Override public String call() throws Exception { return "1"; } } FutureTask stringFutureTask = new FutureTask<>(new Callable1()); stringFutureTask.run();
使用流创建
其实本质是通过 Lambda(拉姆达)表示创建线程,也就是得到一个 Runnable 接口的实例。
Runnable runnable = () -> { System.out.println("createThreadForStream"); }; new Thread(runnable).start();
ForkJoinPool 线程池
ForkJoinPool:Java提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合成总的计算结果。ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池。ForkJoinPool提供了如下两个常用的构造器。
public ForkJoinPool(int parallelism)
:创建一个包含parallelism个并行线程的ForkJoinPool。public ForkJoinPool()
:以 Runtime.getRuntime().availableProcessors()
的返回值作为 parallelism 来创建 ForkJoinPool。
创建ForkJoinPool实例后,可以调用 ForkJoinPool 的 submit(ForkJoinTask task) 或者invoke(ForkJoinTask task) 来执行指定任务。其中 ForkJoinTask 代表一个可以并行、合并的任务。ForkJoinTask 是一个抽象类,它有两个抽象子类:RecursiveAction 和 RecursiveTask。
- RecursiveTask:代表有返回值的任务;
- RecursiveAction:代表没有返回值的任务;
我们就可以通过 RecursiveTask、 RecursiveAction 实例来创建线程。
new ForkJoinPool().submit(new Thread1());
继承 RecursiveAction 无返回值
继承 RecursiveAction
我们可以创建不带返回值的线程对象。
class PrintTask extends RecursiveAction { @Override protected void compute() { System.out.println("RecursiveAction 子类"); } } new ForkJoinPool().submit(new PrintTask());
继承 RecursiveTask 获取返回值
继承 RecursiveTask
我们可以创建带返回值的线程。
class CalcuteTask extends RecursiveTask { @Override protected Integer compute() { return 10; } } Executors.newSingleThreadExecutor().submit(new CalcuteTask()); ForkJoinTask submit = new ForkJoinPool().submit(new CalcuteTask()); Integer res = submit.get();
使用线程池
ThreadPoolExecutor
是我们创建线程池的核心工具类,我们创建线程池后。execute
或者 submit
方法提交线程执行任务,进入线程池中。等待线程池为我们分配资源执行。并且 ThreadPoolExecutor 提供了非常丰富的线程池配置参数。
通过 ThreadPoolExecutor
创建线程池,也是 Alibaba java 编程规范中倡导的变成方式。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 2, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)); threadPoolExecutor.execute(new Thread1());
使用并发包 Executors
Executors
其实就是对 ThreadPoolExecutor
的封装,是一个典型的工厂方法模式。提供了非常多的创建线程池的方法。比如:
- public static ExecutorService newFiexedThreadPool(int Threads) 创建固定数目线程的线程池。
- public static ExecutorService newCachedThreadPool():创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果没有可用的线程,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
- public static ExecutorService newSingleThreadExecutor():创建一个单线程的Executor。
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
Executors.newSingleThreadExecutor().execute(new Thread1()); Executors.newFixedThreadPool(8).execute(new Thread1()); Executors.newWorkStealingPool(8).execute(new Thread1()); Executors.newCachedThreadPool().execute(new Thread1()); Executors.newSingleThreadScheduledExecutor().schedule(new Thread1(), 2, TimeUnit.SECONDS); Executors.newScheduledThreadPool(8).schedule(new Thread1(), 2, TimeUnit.SECONDS);
总结
Java 创建线程任务过后,JVM 底层会创建一个 JavaThread 和一个 OSThread, 将 Java 线程对象和操作系统内核态的进程绑定。