Java并发包——使用新的方式创建线程
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并发包——使用新的方式创建线程的更多相关文章
- Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析
目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...
- python用类的方式创建线程---自创建类
用类的方式创建线程---自创建类 import threadingimport time class MyThread(threading.Thread):#自建MyThread类继承threadin ...
- 牛客网Java刷题知识点之四种不同的方式创建线程
不多说,直接上干货! 有4种方式可以用来创建线程: 第一种:继承Thread类,重写run方法 第二种:实现Runnable接口,并实现该接口的run方法(一般我们在编程的时候推荐用这种) 第三种:实 ...
- Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析
目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...
- 使用Callable接口创建线程和使用线程池的方式创建线程
1.使用Callable接口的方式实现多线程,这是JDK5.0新增的一种创建多线程的方法 package com.baozi.java2; import java.util.concurrent.Ca ...
- 多线程01.newThread的方式创建线程
1.java应用程序的main函数是一个线程,是被jvm启动的时候调用,线程的名字叫main 2.实现一个线程,必须创建一个thread实例,override run方法,并且调用start方法. 3 ...
- python 以面向对象的方式创建线程 实现售票系统
---恢复内容开始--- 转载或借鉴请注明转自http://www.cnblogs.com/FG123/p/5068556.html 谢谢! 通过面向对象的方法实现多线程,其核心是继承thread ...
- 使用匿名内部类和lamda的方式创建线程
1.匿名内部类的方式 1 /** 2 *匿名内部类的方式启动线程 3 */ 4 public class T2 { 5 public static void main(String[] args) { ...
- Java并发编程:Java创建线程的三种方式
目录 引言 创建线程的三种方式 一.继承Thread类 二.实现Runnable接口 三.使用Callable和Future创建线程 三种方式的对比 引言 在日常开发工作中,多线程开发可以说是必备技能 ...
随机推荐
- R Programming week1-Reading Data
Reading Data There are a few principal functions reading data into R. read.table, read.csv, for read ...
- AutoIt简单使用
以上是自己在公司做培训的PPT首页,其实在线的中文参考文档很全面,很值得学习的.
- C3P0连接池参数配置说明
C3P0连接池参数配置说明 created by cjk on 2017.8.15 常用配置 initialPoolSize:连接池初始化时创建的连接数,default : 3(建议使用) minPo ...
- idea拉出Output窗口和还原窗口
拉出:按住标题可以拖出 效果: 还原:点击restore layout
- JFinal怎么更改项目服务的端口
如图所示,运行时启动的端口是80,现在将它改成801: 可以在Debug configuration 或 Run configuration 弹出的窗口中配置,方法右击项目>properties ...
- 开源敏捷测试管理& 开源BUG跟踪管理软件itest(爱测试) V3.3.0隆重发布
v3.3.0 下载地址 :itest下载 码云源码地址 https://gitee.com/itestwork/itest 开源中国 itest项目地址 https://www.oschina. ...
- npm run build报错(npm ERR! code ELIFECYCLE)的解决办法
具体报错如下图: 环境:centos7 应该node_modules安装问题,我们需要重新安装 rm -rf node_modules rm package-lock.json npm cache c ...
- String与常量池(JDK1.8)
---- 基础知识 String是final类, 并且其方法都被final修饰 String通过char数组来保存字符串 对String对象的任何操作都不会影响到原来的String对象, 所有的改变都 ...
- mysql事物隔离
1.读未提交(行锁) 会发生脏读,事物未提交被其他事物看到,未提交的数据为脏数据. 2.读已提交(行锁) 会发生不可重复读,事物开始时,只能看到已经提交了的事物修改. 3.重复读(行锁) 该级别保证了 ...
- ResNet,DenseNet
目录 ResNet BOOM Why call Residual? 发展史 Basic Block Res Block ResNet-18 DenseNet ResNet 确保20层能训练好的前提下, ...