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创建线程 三种方式的对比 引言 在日常开发工作中,多线程开发可以说是必备技能 ...
随机推荐
- JavaScript - try catch finally throw
语法: try { tryCode - 尝试执行代码块 } catch(err) { catchCode - 捕获错误的代码块 } finally { finallyCode - 无论 try / c ...
- C#中的事件机制
这几天把事件学了一下,总算明白了一些.不多说了,直接代码. class Program { static void Main(string[] args) { CatAndMouse h = new ...
- [Windows Server 2008] IIS配置伪静态方法(Web.config模式的IIS rewrite)
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装伪静态(w ...
- 迅为7寸工业平板电脑|人机界面|工业触摸屏|工控机|HMI|工业显示器
型号:iTOP-HMI070-C 7寸工业平板电脑特点: 1.iTOP-HMI070-C(CAN) 7寸工业触摸屏,CAN总线型触摸屏,配有2组独立的串口和一路CAN总线口: 2.串口都支持各种PLC ...
- ZooKeeper系列(二)
Zookeeper的环境配置 一.Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式. 1.单机模式:Zookeeper只运行在一台服务器上,适合测试环境 ...
- Android(java)学习笔记200:JNI之NDK的概念
1.交叉编译 (1)概念 在一个平台(硬件)和os(软件)环境下,编译出另一种平台和os下可以运行的二进制代码. e.g: 电脑端 ...
- golang zip 解压、压缩文件
package utils import ( "archive/zip" "fmt" "io" "io/i ...
- CAD绘制标记(网页版)
主要用到函数说明: MxDraw::GetCursorPickRect 返回拾取矩形框的宽度,默认值为6.详细说明如下: 参数 说明 IN MXDRAWOCXHANDLE hOcx 控件窗口句柄 OU ...
- 花括号的使用 printf %${width}s , 否则会 去找 $widths
花括号的使用 printf %${width}s , 否则会 去找 $widths 1 #! /usr/bin/perl 2 use strict; 3 use warnings; 4 ...
- 第2节 mapreduce深入学习:7、MapReduce的规约过程combiner
第2节 mapreduce深入学习:7.MapReduce的规约过程combiner 每一个 map 都可能会产生大量的本地输出,Combiner 的作用就是对 map 端的输出先做一次合并,以减少在 ...