文章目录
一. FutureTask
单独使用Runnable时,无法获得返回值,并且Thread类只支持Runnable,所以添加了 FutureTask,Future 和 Callable 类。
单独使用Callable时,无法在新线程中(new Thread(Runnable r))使用,只能使用ExecutorService,于是有了 Future 可以根据 Callable 构建线程
由于 Future 只是一个接口,无法直接创建对象,因此有了 FutureTask
- 作用
- FutureTask实现了Runnable和Future,兼顾两者优点,既可以使用ExecutorService,也可以使用Thread
- 可以取消的异步的计算任务,它的计算是通过Callable实现的,它等价于可以携带结果的Runnable
- 实现接口
Runnable
Callable
- 用于实现并行执行的接口。它与 Runnable 接口非常相似,但是它不返回任何值,而 Callable 必须在执行结束时返回一个值
Future
- 封装并行调用的类,可以取消任务的执行,确定执行是否已成功完成或出错,以及其他操作
二. Callable接口 vs Runnable接口
Runnable | Callable | |
---|---|---|
核心方法 | run()方法 | call()方法 |
返回值 | 无 | 有 |
异常 | run()方法不可以声明抛出异常 | call()方法可以声明抛出异常 |
线程(池) | executors、thread | executors |
相同点 | 接口,调用Thread.start()启动线程 | 接口,调用Thread.start()启动线程 |
三. ThreadPoolExecutor
线程池:
- 加快响应速度。消除了线程创建带来的延时
- 合理的利用CPU和内存。控制线程的数量,既不会因为线程太多导致内存溢出,也不会因为太少导致CPU资源的浪费
- 便于统一管理线程
// ThreadPoolExecutor 构造器
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
参数含义
- 7个参数,其中前5个是必要参数,后两个(线程工厂和拒绝策略)可选。
参数 | 类型 | 含义 |
---|---|---|
corePoolSize | int | 核心池大小,表示线程池维护线程的最少数量 |
maximumPoolSize | int | 最大池大小,表示线程池维护线程的最大数量 |
keepAliveTime | long | 线程池维护线程所允许的空闲时间 |
workQueue | BlockingQueue | 阻塞队列,表示如果任务数量超过核心池大小,多余的任务添加到阻塞队列中 |
unit | TimeUnit | 线程池维护线程所允许的空闲时间的单位 |
threadFactory | ThreadFactory | 线程工厂,线程池需要新的线程时,生成新的线程 |
handler | RejectedExecutionHandler | 拒绝策略,线程池对拒绝任务的处理策略 |
四.volatile
关键字
volatile相当于一个轻量级的sychronize,不会引起线程的上下文切换
- 作用:
-
保证内存可见性,但不能保证变量的原子性
- 线程A对一个volatile变量的修改,对于其它线程来说是可见的,即线程每次获取volatile变量的值都是最新的
- 如:后缀++的操作,无法通过volatile保证结果准确性的,因为其不具有原子性
-
禁止指令重排
- 举例:
class Resource implements Runnable {
volatile public int i;
public Resource(int _i){
i = _i;
}
public void run(){
while(true){
if (i>0){
try{
Thread.sleep(200);
}
catch(Exception e){}
i--; // 不具备原子性
System.out.println(Thread.
currentThread().getName()+" "+i);
}
else{
System.out.println(Thread.
currentThread().getName());
break;
}
}
}
}
public class TestSecurity{
public static void main(String[] args){
Resource m = new Resource(9);
Thread t1 = new Thread(m);
Thread t2 = new Thread(m);
t1.start();
t2.start();
}
}
/*
某次运行结果:
Thread-0 7
Thread-1 7
Thread-1 6
Thread-0 5
Thread-1 4
Thread-0 4
Thread-0 3
Thread-1 3
Thread-1 2
Thread-0 2
Thread-1 1
Thread-0 0
Thread-0
Thread-1 -1
Thread-1
结果并不准确
*/
五. Java实现互斥的同步机制
监视器(monitor)和 synchronized
- 用法:
- synchronized 代码块:监视器就是指定的对象
- synchronized 方法:监视器就是 this 对象
- synchronized 静态方法:监视器就是相应的类
ReentrantLock类
六. 线程应用
- 烧水泡茶最优工序
class MakeThread2 extends Thread{
public void run() {
System.out.println();
System.out.print(this.getName() + ": 洗茶壶(1分钟)->");
try {
Thread.sleep(1000);
}
catch(Exception e) {
System.out.println(e);
}
System.out.print("洗茶杯(2分钟)->");
try {
Thread.sleep(2000);
}
catch(Exception e) {
System.out.println(e);
}
System.out.println("拿茶叶(1分钟)");
}
}
class MakeThread1 extends Thread{
MakeThread2 m2 = new MakeThread2();
public void run() {
System.out.print(this.getName() + ":洗水壶(1分钟)->");
try {
Thread.sleep(1000);
}
catch(Exception e) {
System.out.println(e);
}
System.out.println("烧水(15分钟)->等待");
System.out.print(" |");
m2.start();
try {
this.sleep(11000);
}
catch (InterruptedException e) {
System.out.println(e);
}
System.out.println();
System.out.println(this.getName() + ":泡茶,共用16分钟");
}
}
public class Make{
public static void main(String[] args) {
MakeThread1 m1 = new MakeThread1();
m1.start();
}
}
运行结果:
- Java并发包的Lock及Conditon改写例9.11
import java.util.concurrent.locks.*;
class Account{
volatile private int value;
//布尔标志
volatile private boolean isMoney = false;
private final ReentrantLock lock = new ReentrantLock();
// 存钱的 Condition 对象
private Condition SaveCondition = lock.newCondition();
// 取钱的 Condition 对象
private Condition FetchCondition = lock.newCondition();
void put(int i) {
lock.lock(); //使用锁取代同步方法
try{
while(isMoney){
try{
SaveCondition.await(); //存钱线程等待
} catch(Exception e){}
}
value = value + i;
System.out.println("存入"+i+" 账上金额为:"+value);
isMoney = true;//设置标志
FetchCondition.signal(); //唤醒等待资源的取钱线程
} finally {
lock.unlock();
}
}
int get(int i) {
lock.lock();
try{
while(!isMoney ){
try {
FetchCondition.await(); //取钱线程等待
} catch(Exception e){}
}
if (value>i)
value = value - i;
else {
i = value;
value = 0;
}
System.out.println("取走"+i+" 账上金额为:"+value);
isMoney = false;
SaveCondition.signal(); //唤醒等待资源的存钱线程
return i;
} finally {
lock.unlock();
}
}
}
- 生产者/消费者模式
/**
* 代码来源:
* 程序猿学社 - https://ithub.blog.csdn.net/
*/
public class Pile {
//库存数量
private int sum=0;
private int max=10;
/**
* 生产者
*/
public synchronized void pro(){
while (sum == max){ //达到最大值说明库存已经满了,无法存放充电桩
try {
this.wait(); //需要等待消费者,消费后,才能生存
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sum++;
System.out.println(Thread.currentThread().getName()+":剩余充电桩数量为"+sum);
this.notifyAll(); //通知消费者,我们库存有充电桩,赶紧来消费
}
/**
* 消费者
*/
public synchronized void consumer(){
while (sum == 0){
try {
this.wait(); //说明库房,充电桩不够了,需要等待充电桩厂家,继续生产充电桩
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sum --;
System.out.println(Thread.currentThread().getName()+":剩余充电桩数量为"+sum);
this.notifyAll(); //通知生产厂家,我已经消费了,你可以继续生产充电桩
}
}
测试类:
/**
* 代码来源:
* 程序猿学社 - https://ithub.blog.csdn.net/
*/
public class Demo1{
public static void main(String[] args) {
Pile pile = new Pile();
for (int j = 0; j < 3; j++) {
new Thread(()->{
for (int i = 0; i < 15; i++) {
pile.pro();
}
},"生产者"+j).start();
new Thread(()->{
for (int i = 0; i < 15; i++) {
pile.consumer();
}
},"消费者"+j).start();
}
}
}
总结
在整理博客的过程中参考了一些资料以及许多他人优秀的文章,就不一一列举,在此表示感谢。