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. JavaScript - try catch finally throw

    语法: try { tryCode - 尝试执行代码块 } catch(err) { catchCode - 捕获错误的代码块 } finally { finallyCode - 无论 try / c ...

  2. C#中的事件机制

    这几天把事件学了一下,总算明白了一些.不多说了,直接代码. class Program { static void Main(string[] args) { CatAndMouse h = new ...

  3. [Windows Server 2008] IIS配置伪静态方法(Web.config模式的IIS rewrite)

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装伪静态(w ...

  4. 迅为7寸工业平板电脑|人机界面|工业触摸屏|工控机|HMI|工业显示器

    型号:iTOP-HMI070-C 7寸工业平板电脑特点: 1.iTOP-HMI070-C(CAN) 7寸工业触摸屏,CAN总线型触摸屏,配有2组独立的串口和一路CAN总线口: 2.串口都支持各种PLC ...

  5. ZooKeeper系列(二)

    Zookeeper的环境配置 一.Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式. 1.单机模式:Zookeeper只运行在一台服务器上,适合测试环境 ...

  6. Android(java)学习笔记200:JNI之NDK的概念

    1.交叉编译 (1)概念 在一个平台(硬件)和os(软件)环境下,编译出另一种平台和os下可以运行的二进制代码. e.g:     电脑端                               ...

  7. golang zip 解压、压缩文件

    package utils import (    "archive/zip"    "fmt"    "io"    "io/i ...

  8. CAD绘制标记(网页版)

    主要用到函数说明: MxDraw::GetCursorPickRect 返回拾取矩形框的宽度,默认值为6.详细说明如下: 参数 说明 IN MXDRAWOCXHANDLE hOcx 控件窗口句柄 OU ...

  9. 花括号的使用 printf %${width}s , 否则会 去找 $widths

    花括号的使用  printf %${width}s , 否则会 去找  $widths 1 #! /usr/bin/perl   2 use strict;  3 use warnings;  4   ...

  10. 第2节 mapreduce深入学习:7、MapReduce的规约过程combiner

    第2节 mapreduce深入学习:7.MapReduce的规约过程combiner 每一个 map 都可能会产生大量的本地输出,Combiner 的作用就是对 map 端的输出先做一次合并,以减少在 ...