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>  futureTasks=new ArrayList<>();
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i <10; i++) {
            FutureTask 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 task:futureTasks){
            try{
                res+=task.get();

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

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

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

关注微信公众号:【入门小站】,解锁更多知识点

你可能感兴趣的:(java,多线程)