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创建线程 三种方式的对比 引言 在日常开发工作中,多线程开发可以说是必备技能 ...
随机推荐
- 5.1点击4个按钮显示相应的div
事件:onclick 属性:display,className 用到for语句,index标记,this当前事件 先清空后附加 <!DOCTYPE html><html>< ...
- 镜像中的 Everything, GnomeLive ,KdeLive ,livecd ,NetInstall的区别?
everything: 对完整版安装盘的软件进行补充,集成所有软件 GnomeLive , GNOME桌面版 KdeLive , KDE桌面版 livecd 光盘上运行的系统 ,NetInstall ...
- 迅为电子4.3寸CAN总线工业平板电脑简介
型号:iTOP-HMI043-C 4.3寸CAN总线工业平板电脑支持CAN通讯显示器,显示:显示尺寸:4.3英寸:分辨率:480×272 TFT液晶 65536色 :接口:支持CAN 2.0B:USB ...
- (转)淘淘商城系列——使用maven构建工程
http://blog.csdn.net/yerenyuan_pku/article/details/72669269 开发工具和环境 这里,我统一规范一下淘淘商城的开发工具和环境,如下: Eclip ...
- CREATE AGGREGATE - 定义一个新的聚集函数
SYNOPSIS CREATE AGGREGATE name ( BASETYPE = input_data_type, SFUNC = sfunc, STYPE = state_data_type ...
- CAD参数绘制对齐标注(com接口)
主要用到函数说明: _DMxDrawX::DrawDimAligned 绘制一个对齐标注.详细说明如下: 参数 说明 DOUBLE dExtLine1PointX 第一条界线开始点X值 DOUBLE ...
- gprc-java与golang分别实现服务端,客户端,跨语言通信(一.java实现)
1.在pom中引入 <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty< ...
- 【C语言】控制台窗口图形界面编程(一)句柄和文本属性
目录 00. 目录 01. 句柄 02. GetStdHandle函数 03. CloseHandle函数 04. SetConsoleTextAttribute函数 05. 十进制颜色对照表 06. ...
- viewstate 与 session 区别
Session存在于服务器端可以跨页面.耗费服务器资源.ViewState载体是页面文件,消耗带宽. EG: viewstate是存储在客户端的隐藏信息,当服务器接受请求回传时可以将viewstate ...
- Tab键可访问的下拉菜单demo
<ul id="navigationRegion"> <li token="1" class="index_on"> ...