[TOC]
## 1. 继承Thread类
通过继承Thread类来创建并启动多线程的步骤如下:
**1. 定义一个类继承Thread类,并重写Thread类的run()方法,run()方法的方法体就是线程要完成的任务,因此把run()称为线程的执行体;**
**2. 创建该类的实例对象,即创建了线程对象;**
**3. 调用线程对象的start()方法来启动线程;**
~~~
package com.tuna.javatest.thread;
public class ExtendThread extends Thread {
private int i;
public void run() {
for (; i < 10; i++) {
//当通过继承Thread类的方式实现多线程时,可以直接使用this获取当前执行的线程
System.out.println(this.getName() + " " + i);
}
}
public static void main(String[] args) {
for (int j = 0; j < 5; j++) {
//调用Thread类的currentThread()方法获取当前线程
System.out.println(Thread.currentThread().getName() + " " + j);
//创建并启动第一个线程
new ExtendThread().start();
}
}
}
~~~
## 2. 实现Runnable接口
这种方式创建并启动多线程的步骤如下:
**1. 定义一个类实现Runnable接口;**
**2. 创建该类的实例对象obj;**
**3. 将obj作为构造器参数传入Thread类实例对象,这个对象才是真正的线程对象;**
**4. 调用线程对象的start()方法启动该线程;**
推荐这种写法,体现设计与实现分离的思想
~~~
package com.tuna.javatest.thread;
public class ImpRunnable implements Runnable {
private int i;
@Override
public void run() {
for(;i < 5;i++) {
//当线程类实现Runnable接口时,要获取当前线程对象只有通过Thread.currentThread()获取
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
public static void main(String[] args) {
for(int j = 0;j < 30;j++) {
System.out.println(Thread.currentThread().getName() + " " + j);
ImpRunnable thread_target = new ImpRunnable();
new Thread(thread_target,j+"").start();
}
}
}
~~~
## 3. Callable和Future接口创建线程
### 3.1 Callable接口
通过实现Runnable接口创建多线程时,Thread类的作用就是把run()方法包装成线程的执行体,那么,是否可以直接把任意方法都包装成线程的执行体呢?从JAVA5开始,JAVA提供提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更强大,call()方法的功能的强大体现在:
1. call()方法可以有返回值;
2. call()方法可以声明抛出异常;
从这里可以看出,完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是call()方法。但问题是:Callable接口是JAVA新增的接口,而且它不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。还有一个原因就是:call()方法有返回值,call()方法不是直接调用,而是作为线程执行体被调用的,所以这里涉及获取call()方法返回值的问题。
于是,JAVA5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该类实现了Future接口,并实现了Runnable接口,所以FutureTask可以作为Thread类的target,同时也解决了Callable对象不能作为Thread类的target这一问题。
### 3.2 Future接口
是对于具体的Runnable或者Callable任务的执行结果进行**取消**、**查询是否完成**、**获取结果** 。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
接口中有5中方法:
1. **cancel(boolean mayInterruptIfRunning)**
方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。
参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
2. **isCancelled()**
方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
3. **isDone()**
方法表示任务是否已经完成,若任务完成,则返回true;
4. **get()**
方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
5. **get(long timeout, TimeUnit unit)**
用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。可用在任务超时控制的情形。
### 3.3 线程实现
1. 实现Callable接口并重写call方法,完成要执行的逻辑
~~~
class Task implements Callable<Object> {
private String args1;
private String args2;
//构造函数,用来向task中传递任务的参数
public Task(String args1,String args2) {
this.args1=args1;
this.args2=args2;
}
//任务执行的动作
@Override
public Object call() throws Exception {
for(int i=0;i<10;i++){
System.out.println("call执行任务!");
}
return true;
}
}
~~~
2. 创建FutureTask对象(传入),将逻辑交给线程
```
public static void main(String[] args) {
Task myTask = new Task("11", "22");//实例化任务,传递参数
FutureTask<Object> futureTask = new FutureTask(myTask);//将任务放进FutureTask里
//采用thread来开启多线程,futuretask继承了Runnable,可以放在线程池中来启动执行
Thread thread = new Thread(futureTask);
thread.start();
try {
//get():获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常,
//如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。
boolean result = (boolean) futureTask.get();
System.out.println("result:" + result );
} catch (Exception e) {
e.printStackTrace();
}
}
```
3. 完整代码
~~~
class Task implements Callable<Object> {
private String args1;
private String args2;
//构造函数,用来向task中传递任务的参数
public Task(String args1,String args2) {
this.args1=args1;
this.args2=args2;
}
//任务执行的动作
@Override
public Object call() throws Exception {
for(int i=0;i<10;i++){
System.out.println("call执行任务!");
}
return true;
}
public static void main(String[] args) {
Task myTask = new Task("11", "22");//实例化任务,传递参数
FutureTask<Object> futureTask = new FutureTask(myTask);//将任务放进FutureTask里
//采用thread来开启多线程,futuretask继承了Runnable,可以放在线程池中来启动执行
Thread thread = new Thread(futureTask);
thread.start();
try {
//get():获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常,
//如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。
boolean result = (boolean) futureTask.get();
System.out.println("result:" + result );
} catch (Exception e) {
e.printStackTrace();
}
}
}
~~~
```
call执行任务!
call执行任务!
call执行任务!
call执行任务!
call执行任务!
call执行任务!
call执行任务!
call执行任务!
call执行任务!
call执行任务!
result:true
```
- 计算机网络
- 基础_01
- tcp/ip
- http转https
- Let's Encrypt免费ssl证书(基于haproxy负载)
- what's the http?
- 网关
- 网络IO
- http
- 工具
- Git
- 初始本地仓库并上传
- git保存密码
- Gitflow
- maven
- 1.生命周期命令
- 聚合与继承
- 插件管理
- assembly
- 资源管理插件
- 依赖范围
- 分环境打包
- dependencyManagement
- 版本分类
- 找不到主类
- 无法加载主类
- 私服
- svn
- gradle
- 手动引入第三方jar包
- 打包exe文件
- Windows
- java
- 设计模式
- 七大原则
- 1.开闭原则
- 2. 里式替换原则
- 3. 依赖倒置原则
- 4. 单一职责原则
- 单例模式
- 工厂模式
- 简单工厂
- 工厂方法模式
- 抽象工厂模式
- 观察者模式
- 适配器模式
- 建造者模式
- 代理模式
- 适配器模式
- 命令模式
- json
- jackson
- poi
- excel
- easy-poi
- 规则
- 模板
- 合并单元格
- word
- 读取
- java基础
- 类路径与jar
- 访问控制权限
- 类加载
- 注解
- 异常处理
- String不可变
- 跨域
- transient关键字
- 二进制编码
- 泛型1
- 与或非
- final详解
- Java -jar
- 正则
- 读取jar
- map
- map计算
- hashcode计算原理
- 枚举
- 序列化
- URLClassLoader
- 环境变量和系统变量
- java高级
- java8
- 1.Lambda表达式和函数式接口
- 2.接口的默认方法和静态方法
- 3.方法引用
- 4.重复注解
- 5.类型推断
- 6.拓宽注解的应用场景
- java7-自动关闭资源机制
- 泛型
- stream
- 时区的正确理解
- StringJoiner字符串拼接
- 注解
- @RequestParam和@RequestBody的区别
- 多线程
- 概念
- 线程实现方法
- 守护线程
- 线程阻塞
- 笔试题
- 类加载
- FutureTask和Future
- 线程池
- 同步与异步
- 高效简洁的代码
- IO
- ThreadLocal
- IO
- NIO
- 图片操作
- KeyTool生成证书
- 压缩图片
- restful
- 分布式session
- app保持session
- ClassLoader.getResources 能搜索到的资源路径
- java开发规范
- jvm
- 高并发
- netty
- 多线程与多路复用
- 异步与事件驱动
- 五种IO模型
- copy on write
- code style
- 布隆过滤器
- 笔试
- 数据库
- mybatis
- mybatis与springboot整合配置
- pagehelper
- 分页数据重复问题
- Java与数据库之间映射
- 拦截器
- 拦截器应用
- jvm
- 堆内存测试
- 线程栈
- 直接内存
- 内存结构
- 内存模型
- 垃圾回收
- 调优
- 符号引用
- 运行参数
- 方法区
- 分带回收理论
- 快捷开发
- idea插件
- 注释模板
- git
- pull冲突
- push冲突
- Excel处理
- 图片处理
- 合并单元格
- easypoi
- 模板处理
- 响应式编程
- reactor
- reactor基础
- jingyan
- 规范
- 数据库