专栏首页JVMGCJava同步组件之Condition,FutureTask
原创

Java同步组件之Condition,FutureTask

Java同步组件概况

  • CountDownLatch : 是闭锁,通过一个计数来保证线程是否一直阻塞
  • Semaphore: 控制同一时间,并发线程数量
  • CyclicBarrier:字面意思是回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。
  • ReentrantLock:是一个重入锁,一个线程获得了锁之后仍然可以反复加锁,不会出现自己阻塞自己的情况。
  • Condition:配合ReentrantLock,实现等待/通知模型
  • FutureTask:FutureTask实现了接口Future,同Future一样,代表异步计算的结果。

Condition

Condition是多线程之间协调通信的工具类,除了有AQS,还有可能存在Condition队列(不存在或者存在一个以上,即多个等待队列)

某个或某些线程等待某个Condition,只有当该条件具备(signal或者signAll方法被调用)时,这些等待线程才会被唤醒,从而重新争夺锁。

Condition是同步器AbstractQueuedSynchronized的内部类,因为Condition的操作需要获取相关的锁,所以作为同步器的内部类比较合理。

一个 Condition 包含一个等待队列,Condition拥有首节点firstWaiter和尾节点lastWaiter。当前线程调用Condition.await()方法时,将会以当前线程构造节点,并将节点从尾部加入等待队列。

Condition代码演示

package com.rumenz.task;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {

    public static void main(String[] args) {
        ReentrantLock reentrantLock=new ReentrantLock();
        Condition condition=reentrantLock.newCondition();
        ExecutorService executorService = Executors.newCachedThreadPool();
        AtomicInteger  atomicInteger=new AtomicInteger(0);
        executorService.execute(()->{

            try{
                reentrantLock.lock();
                System.out.println("计算1====开始");
                int i = atomicInteger.addAndGet(10);
                System.out.println("计算1====结果"+i);
                condition.await();
                atomicInteger.incrementAndGet();
                System.out.println("最后结果"+atomicInteger.get());


            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }

        });
        executorService.execute(()->{
            try{
                reentrantLock.lock();

                Thread.sleep(5000);
                System.out.println("计算====2");
                int i = atomicInteger.addAndGet(40);
                System.out.println("计算2====结果"+i);
                condition.signal();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        });

        executorService.shutdown();

    }
}

//计算1====开始
//计算1====结果10
//计算====2
//计算2====结果50
//最后结果51

FutureTask

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

FutureTask代码演示

package com.rumenz.task;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;


public class FutureTaskExample {
    public static void main(String[] args) throws Exception{
        List<FutureTask<Integer>>  futureTasks=new ArrayList<>();
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i <10; i++) {
            FutureTask<Integer> futureTask=new FutureTask<>(()->{
                int res=0;
                for (int j = 0; j < 50; j++) {
                    res+=10;
                }
                return res;
            });
            futureTasks.add(futureTask);
            pool.submit(futureTask);

        }
        System.out.println("所有任务都已经提交,主线程开始干活");
        Thread.sleep(5000);//模拟主线程的任务
        System.out.println("主进程任务完成,开始获取子线程任务结果");

        int res=0;
        for(FutureTask<Integer> task:futureTasks){
            try{
                res+=task.get();

            }catch (Exception e){
                e.printStackTrace();
            }
        }

        pool.shutdown();
        System.out.println("最终计算结果:"+res);
    }
}

//所有任务都已经提交,主线程开始干活
//主进程任务完成,开始获取子线程任务结果
//最终计算结果:5000

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java并发组件浅析

    Java并发相关组件或者技术包括:线程、线程池、阻塞队列、Future/FutureTask、Lock/Condition、Lock、AQS(队列同步器)、并发...

    luoxn28
  • 为什么说LockSupport是Java并发的基石?

    而AQS中的控制线程又是通过LockSupport类来实现的,因此可以说,LockSupport是Java并发基础组件中的基础组件。LockSupport定义了...

    luoxn28
  • Java同步组件之CountDownLatch,Semaphore

    入门小站
  • Java同步组件之CyclicBarrier,ReentrantLock

    入门小站
  • java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?

    java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求:

    路人甲Java
  • 【Java源码】AQS 解析

    AQS 即 AbstractQueuedSynchronizer,是 java.util.concurrent.locks 包的一个重要概念。Java 中锁实现...

    程序员架构进阶
  • 【Java 源码解析】AQS

    AQS 即 AbstractQueuedSynchronizer,是 java.util.concurrent.locks 包的一个重要概念。Java 中锁实现...

    程序员架构进阶
  • Java并发之Condition 并发同步控制

    项目地址:https://github.com/windwant/windwant-demo/tree/master/thread-demo

    WindWant
  • 快速学习-JUC

    在 Java 5.0 提供了 java.util.concurrent (简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自...

    cwl_java
  • bat等大公司常考多线程面试题【力荐】

    思考题:希望大家积极的思考,并且可以踊跃的说出自己的想法,想法不管对与错,只要说出来就是一种提高,所以,希望小伙伴们可以把自己的想法在留言区给出,这样大家也可以...

    好好学java
  • BATJ面试必会之并发篇

    调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用“使一个线程睡眠”进行描述。

    乔戈里
  • java高并发系列 - 第19天:JUC中的Executor框架详解1

    Executors框架是Doug Lea的神作,通过这个框架,可以很容易的使用线程池高效地处理并行任务。

    路人甲Java
  • Java多线程并发面试问答

    原子操作在单个任务单元中执行,而不受其他操作的干扰。在多线程环境中,原子操作是必需的,以避免数据不一致。

    淡定的蜗牛
  • 突击并发编程JUC系列-启航篇

    Java 并发编程对于开发者来说是难点也是重点,想要掌握学会并发编程,并不是一件很容易的事情,从本篇文章跟我一起攻克 Java并发编程JUC系列教程吧。

    山间木匠
  • Java 线程 Executor 框架详解与使用

    在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当该Java线程终止时,这个操作系...

    哲洛不闹
  • 并发编程-15并发容器(J.U.C)核心 AbstractQueuedSynchronizer 抽象队列同步器AQS介绍

    并发编程-14线程安全策略之并发容器(J.U.C)中的集合类中介绍了J.U.C中的Collections集合 ,这篇博文我们将继续来看下J.U.C中的 AQS抽...

    小小工匠
  • Java并发编程73道面试题及答案 —— 面试稳了

    最近后台和微信理有很多读者让我整理一些面试题,我就把这事放在心上了,于是在各大网站和其他公众号里面搜索面试相关的高质量文章或者信息,今天主要整理一下 Java ...

    java思维导图
  • 并发编程-19AQS同步组件之重入锁ReentrantLock、 读写锁ReentrantReadWriteLock、Condition

    重入锁ReentrantLock,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对 资源的重复加锁,而不会造成自己阻塞自己。

    小小工匠
  • 一文搞定Java并发编程面试考点

    任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon(bool on);true则把该线程设置为守护线程,反之则为用户线程。Thre...

    Bug开发工程师

扫码关注云+社区

领取腾讯云代金券