Java并发包——使用新的方式创建线程

摘要:本文主要学习了如何使用Java并发包中的类创建线程。

部分内容来自以下博客:

https://www.cnblogs.com/dolphin0520/p/3949310.html

使用Callable接口创建线程

Callable与Runnable

之前学习多线程的时候,使用java.lang包下的Runnable接口可以创建线程。

 @FunctionalInterface
public interface Runnable {
public abstract void run();
}

发现由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。

Callable位于java.util.concurrent包下,它是一个函数式接口,在它里面声明了一个方法,只不过这个方法叫做call()。

 @FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}

通过源码可以看到call()方法是一个泛型接口,可以返回V类型的数据,并且支持抛出异常。

Future

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

Future类位于java.util.concurrent包下,它是一个接口:

 public interface Future<V> {
// 用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。
// 参数mayInterruptIfRunning表示是否允许取消正在执行的任务,如果设置true,则表示可以取消正在执行过程中的任务。
// 如果任务已经完成,返回false。
// 如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false。
// 如果任务还没有执行,返回true。
boolean cancel(boolean mayInterruptIfRunning); // 表示正在执行的任务是否被取消成功,如果在完成前被取消成功,返回true。
boolean isCancelled(); // 表示任务是否已经完成,若任务完成,则返回true。
boolean isDone(); // 用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回。
V get() throws InterruptedException, ExecutionException; // 用来获取执行结果,如果在指定时间内,还没获取到结果,就抛出TimeoutException异常。
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。

FutureTask

我们先来看一下FutureTask的实现:

 public class FutureTask<V> implements RunnableFuture<V>

FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

 public interface RunnableFuture<V> extends Runnable, Future<V>

可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

FutureTask提供了2个构造器:

public FutureTask(Callable<V> callable);

public FutureTask(Runnable runnable, V result);

创建线程并使用

代码如下:

 public class Demo {
public static void main(String[] args) {
FutureTask<Integer> futureTask = new FutureTask<Integer>(new NewFutureTask());
new Thread(futureTask).start();
try {
Integer i = futureTask.get();
System.out.println(i);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
} class NewFutureTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("call() ...");
return 100;
}
}

运行结果如下:

 call() ...
100

因为FutureTask实现了RunnableFuture接口,而RunnableFuture又继承了Runnable和Future接口,所以FutureTask可以看作是Runnable的一个实现类。

所以在创建线程的时候,代码 new Thread(futureTask).start(); 实际上是通过 public Thread(Runnable target) 方法创建的线程。

使用线程池创建线程

Executor

Executor接口是线程池的顶层接口,ExecutorService接口是Executor的子接口,而ThreadPoolExecutor类实现了ExecutorService接口,是线程池的核心类。

Executors类时线程池的一个工具类,里面提供了创建线程池的几个静态方法。

下面的代码展示了使用Executors类的newFixedThreadPool()方法创建一个固定长度的线程池,并向线程池中插入任务的操作:

 public class Demo {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(3); for (int i = 1; i <= 11; i++) {
DemoThread dt = new DemoThread(i);
threadPool.submit(dt);
}
threadPool.shutdown();
}
} class DemoThread implements Runnable {
int taskNo = 0; public DemoThread(int taskNo) {
this.taskNo = taskNo;
} @SuppressWarnings("static-access")
public void run() {
try {
System.out.println("task " + taskNo);
Thread.currentThread().sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

结果如下:

 task 1
task 3
task 2// 此处有等待。
task 4
task 5
task 6// 此处有等待。
task 7
task 9
task 8// 此处有等待。
task 10
task 11

结果说明:

可以看到因为设置的线程数为3,所以在创建了3个线程之后,将剩下的任务放在了任务队列里,当有任务执行完成之后再将其取出执行。

Java并发包——使用新的方式创建线程的更多相关文章

  1. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  2. python用类的方式创建线程---自创建类

    用类的方式创建线程---自创建类 import threadingimport time class MyThread(threading.Thread):#自建MyThread类继承threadin ...

  3. 牛客网Java刷题知识点之四种不同的方式创建线程

    不多说,直接上干货! 有4种方式可以用来创建线程: 第一种:继承Thread类,重写run方法 第二种:实现Runnable接口,并实现该接口的run方法(一般我们在编程的时候推荐用这种) 第三种:实 ...

  4. Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析

    目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...

  5. 使用Callable接口创建线程和使用线程池的方式创建线程

    1.使用Callable接口的方式实现多线程,这是JDK5.0新增的一种创建多线程的方法 package com.baozi.java2; import java.util.concurrent.Ca ...

  6. 多线程01.newThread的方式创建线程

    1.java应用程序的main函数是一个线程,是被jvm启动的时候调用,线程的名字叫main 2.实现一个线程,必须创建一个thread实例,override run方法,并且调用start方法. 3 ...

  7. python 以面向对象的方式创建线程 实现售票系统

    ---恢复内容开始--- 转载或借鉴请注明转自http://www.cnblogs.com/FG123/p/5068556.html   谢谢! 通过面向对象的方法实现多线程,其核心是继承thread ...

  8. 使用匿名内部类和lamda的方式创建线程

    1.匿名内部类的方式 1 /** 2 *匿名内部类的方式启动线程 3 */ 4 public class T2 { 5 public static void main(String[] args) { ...

  9. Java并发编程:Java创建线程的三种方式

    目录 引言 创建线程的三种方式 一.继承Thread类 二.实现Runnable接口 三.使用Callable和Future创建线程 三种方式的对比 引言 在日常开发工作中,多线程开发可以说是必备技能 ...

随机推荐

  1. HashMap和List遍历方法总结及如何遍历删除元素

    https://blog.csdn.net/demohui/article/details/77748809

  2. Python 设计模式--简单工厂模式

    简单工厂模式(Factory Pattern)是一种创建型的设计模式,像工厂一样根据要求生产对象实例. 特点:根据不同的条件,工厂实例化出合适的对象. <大话设计模式>中实例:四则运算计算 ...

  3. [ SDOI 2010 ] 古代猪文

    \(\\\) Description 一句话题意: 设 \(x=\sum_{d|n} C_n^d\),求 \(G^x\pmod {999911659}\) . 从原题面大段语文中其实不难推出所求. \ ...

  4. 关于flex布局对自己的影响

    对于本图来说用了一个效果就能达到这种情况,对于我来说,今天是有进步的,具体操作就是盒子模型确实,在什么地方起来的flex就运用到该地方去,刚 开始就一直有问题,思考了半天,原来是我的控制代码出现了点错 ...

  5. HTML中的那些bug

    1.语法检测时提示有多余的结束标签 <!doctype html> <html> <head> <meta charset="utf-8" ...

  6. phpmyadmin在linux下通过sock安装教程

    当初是按照 http://www.cnblogs.com/freeweb/p/5262852.html 地址参考安装,因为疏忽,未考虑到版本差异带来的影响(自身安装的是最新版 phpMyAdmin-4 ...

  7. python中break、continue 、exit() 、pass终止循环的区别

    python中break.continue .exit() .pass区分 1.break:跳出循环,不再执行 Python break语句,就像在C语言中,打破了最小封闭for或while循环. b ...

  8. 迅为iTOP-4418开发板串口虚拟控制台配置为普通串口

    如何将 iTOP-4418 的串口控制台配置为普通串口.在最终的产品中,如果需要额外的串口,可以将调试用的控制台串口作为普通串口使用,因为交付给最终用户手中的产品,一般不需要调试串口.屏蔽串口控制台需 ...

  9. c++ 数组长度

    数组长度求解 sizeof template <class T>int getArrayLen(T &array){ return (sizeof(array) / sizeof( ...

  10. No-2.注释

    01. 注释的作用 使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性 02. 单行注释(行注释) 以 # 开头,# 右边的所有东西都被当做说明文字,而不是真正要执行的程序,只起到 ...