java多线程——线程池

系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互,在需要创建大量生存期很短的线程时,更应该考虑启动新线程的性能成本。因此,在这种情况下应该使用线程池,线程池在系统启动时就创建了大量空闲线程,程序将一个Runnable或Callable对象传给线程池,线程池就会启动一个线程来执行它们的run或call方法,当线程执行完后,并不会死亡,而是再次返回线程池中,成为空闲状态,等待执行下一个Runnable对象的run或call方法。

Java8线程池

java8提供了内建线程池,新增了一个Executors工厂类来产生线程池对象,该工厂的几个静态方法可以提供相应的线程池:

public static ExecutorService newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程会缓存在线程池。

public static ExecutorService newFixedThreadPool(int nThreads):创建指定数量线程的线程池。

public static ExecutorService newSingleThreadExecutor():创建一个线程的线程池。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):指定线程数量,同时在指定延迟后执行线程任务,其返回的对象是ScheduledExecutorService是ExecutorService线程池类的子类。

public static ScheduledExecutorService newSingleThreadScheduledExecutor():产生可延迟执行的单线程线程池。

public static ExecutorService newWorkStealingPool(int parallelism):创建持有足够的线程线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争。生成的线程池是后台线程池,当所有前台线程都死亡了,线程池中线程会自动死亡。

public static ExecutorService newWorkSteallingPool():上一个方法的简化方法,如果当前机器有n个cpu,则目标并行级别被设置为n。生成的线程池也是后台线程池

在线程池对象ExecutorService中,提供了三个方法来提交Runnable和Callable任务。

  • Future submit(Runnable task):提交Runnable,由于Runnable是没有返回值的,所以Future获取的返回值是null。但是可以调用Future对象的isDone()、isCancelled()方法来获得Runnable对象的执行状态。
  • Future submit(Runnable task, T result):提交runnable任务,同时显示地将result作为线程执行完后的返回结果。
  • Future submit(Callable task):提交Callable任务给线程池。

在用完了线程池后,调用shutdown()之后不再接受任务,同时将正在执行的任务和已经提交并在等待执行的任务完成,就销毁线程。执行shudonwNow()则会立即停止所有线程的活动任务,同时暂停处理正在等待的任务,返回等待执行的任务列表。

Java8增强的ForkJoinPool

现在的处理器大多是多核心的,如果将一个任务拆分成多个小任务,并分发到这些核心上并行执行,最后合并结果,可以充分利用cpu的计算能力。ForkJoinPool就提供了这样的功能,其提供了两个构造器:

ForkJoinPool(int parallelism):提供parallelism个并行线程的线程池。

ForkJoinPool():提供Runtime.availableProcessors()方法的返回值作为并行线程池数量。

有了ForkJoinPool实例后,可以调用方法submit(ForkJoinTask task)或invoke(ForkJoinTask task)来执行指定任务。其中ForkJoinTask代表可以并行、合并的任务。ForkJoinTask作为抽象类有两个抽象子类RecursiveTask(有返回值)和RecursiveAction(无返回值)。

class RecursiveActionObject extends RecursiveAction {
    // 重写comput方法
    @Override
    protected void compute() {
        // 声明第一个分解对象
        RecursiveActionObject object1 = new RecursiveActionObject();

        // 声明第二个分解对象
        RecursiveActionObject object2 = new RecursiveActionObject();
        
        // 将分解任务并发运行
        object1.fork();
        object2.fork();

    }
}

 

你可能感兴趣的:(java,java,多线程,线程池)