Java多线程中的concurrent简析

 更新时间:2023年09月12日 09:06:13   作者:flydean程序那些事  
这篇文章主要介绍了Java多线程中的concurrent简析,java.util.concurrent包提供了很多有用的类,方便我们进行并发程序的开发,本文将会挑选其中常用的一些类来进行大概的说明,需要的朋友可以参考下

主要的组件

java.util.concurrent包含了很多内容, 本文将会挑选其中常用的一些类来进行大概的说明:

  • Executor
  • ExecutorService
  • ScheduledExecutorService
  • Future
  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • ThreadFactory

Executor

Executor是一个接口,它定义了一个execute方法,这个方法接收一个Runnable,并在其中调用Runnable的run方法。

我们看一个Executor的实现:

public class Invoker implements Executor {
    @Override
    public void execute(Runnable r) {
        r.run();
    }
}

现在我们可以直接调用该类中的方法:

    public void execute() {
        Executor executor = new Invoker();
        executor.execute( () -> {
            log.info("{}", Thread.currentThread().toString());
        });
    }

注意,Executor并不一定要求执行的任务是异步的。

ExecutorService

如果我们真正的需要使用多线程的话,那么就需要用到ExecutorService了。

ExecutorService管理了一个内存的队列,并定时提交可用的线程。

我们首先定义一个Runnable类:

public class Task implements Runnable {
    @Override
    public void run() {
        // task details
    }
}

我们可以通过Executors来方便的创建ExecutorService:

ExecutorService executor = Executors.newFixedThreadPool(10);

上面创建了一个ThreadPool, 我们也可以创建单线程的ExecutorService:

ExecutorService executor =Executors.newSingleThreadExecutor();

我们这样提交task:

public void execute() { 
    executor.submit(new Task()); 
}

因为ExecutorService维持了一个队列,所以它不会自动关闭, 我们需要调用executor.shutdown() 或者executor.shutdownNow()来关闭它。

如果想要判断ExecutorService中的线程在收到shutdown请求后是否全部执行完毕,可以调用如下的方法:

try {
            executor.awaitTermination( 5l, TimeUnit.SECONDS );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

ScheduledExecutorService

ScheduledExecutorService和ExecutorService很类似,但是它可以周期性的执行任务。

我们这样创建ScheduledExecutorService:

ScheduledExecutorService executorService
                = Executors.newSingleThreadScheduledExecutor();

executorService的schedule方法,可以传入Runnable也可以传入Callable:

Future<String> future = executorService.schedule(() -> {
        // ...
        return "Hello world";
    }, 1, TimeUnit.SECONDS);
    ScheduledFuture<?> scheduledFuture = executorService.schedule(() -> {
        // ...
    }, 1, TimeUnit.SECONDS);

还有两个比较相近的方法:

scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit )
scheduleWithFixedDelay( Runnable command, long initialDelay, long delay, TimeUnit unit ) 

两者的区别是前者的period是以任务开始时间来计算的,后者是以任务结束时间来计算。

Future

Future用来获取异步执行的结果。可以调用cancel(boolean mayInterruptIfRunning) 方法来取消线程的执行。

我们看下怎么得到一个Future对象:

public void invoke() {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    Future<String> future = executorService.submit(() -> {
        // ...
        Thread.sleep(10000l);
        return "Hello world";
    });
}

我们看下怎么获取Future的结果:

if (future.isDone() && !future.isCancelled()) {
    try {
        str = future.get();
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
}

future还可以接受一个时间参数,超过指定的时间,将会报TimeoutException。

try {
    future.get(10, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
    e.printStackTrace();
}

CountDownLatch

CountDownLatch是一个并发中很有用的类,CountDownLatch会初始化一个counter,通过这个counter变量,来控制资源的访问。

我们会在后面的文章详细介绍。

CyclicBarrier

CyclicBarrier和CountDownLatch很类似。CyclicBarrier主要用于多个线程互相等待的情况,可以通过调用await() 方法等待,知道达到要等的数量。

public class Task implements Runnable {
    private CyclicBarrier barrier;
    public Task(CyclicBarrier barrier) {
        this.barrier = barrier;
    }
    @Override
    public void run() {
        try {
            LOG.info(Thread.currentThread().getName() + 
              " is waiting");
            barrier.await();
            LOG.info(Thread.currentThread().getName() + 
              " is released");
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}
public void start() {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
        // ...
        LOG.info("All previous tasks are completed");
    });
    Thread t1 = new Thread(new Task(cyclicBarrier), "T1"); 
    Thread t2 = new Thread(new Task(cyclicBarrier), "T2"); 
    Thread t3 = new Thread(new Task(cyclicBarrier), "T3"); 
    if (!cyclicBarrier.isBroken()) { 
        t1.start(); 
        t2.start(); 
        t3.start(); 
    }
}

Semaphore

Semaphore包含了一定数量的许可证,通过获取许可证,从而获得对资源的访问权限。通过 tryAcquire()来获取许可,如果获取成功,许可证的数量将会减少。

一旦线程release()许可,许可的数量将会增加。

我们看下怎么使用:

static Semaphore semaphore = new Semaphore(10);
public void execute() throws InterruptedException {
    LOG.info("Available permit : " + semaphore.availablePermits());
    LOG.info("Number of threads waiting to acquire: " + 
      semaphore.getQueueLength());
    if (semaphore.tryAcquire()) {
        try {
            // ...
        }
        finally {
            semaphore.release();
        }
    }
}

ThreadFactory

ThreadFactory可以很方便的用来创建线程:

public class ThreadFactoryUsage implements ThreadFactory {
    private int threadId;
    private String name;
    public ThreadFactoryUsage(String name) {
        threadId = 1;
        this.name = name;
    }
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, name + "-Thread_" + threadId);
        log.info("created new thread with id : " + threadId +
                " and name : " + t.getName());
        threadId++;
        return t;
    }
}

到此这篇关于Java多线程中的concurrent简析的文章就介绍到这了,更多相关concurrent简析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 图文示例详解Lucene数据模型查询原理

    图文示例详解Lucene数据模型查询原理

    这篇文章主要为大家通过图文示例详解Lucene数据模型查询原理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 解决JSON.toJSONString首字母大小写的问题

    解决JSON.toJSONString首字母大小写的问题

    这篇文章主要介绍了解决JSON.toJSONString首字母大小写的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • 详解SpringCloud-OpenFeign组件的使用

    详解SpringCloud-OpenFeign组件的使用

    这篇文章主要介绍了SpringCloud-OpenFeign组件的使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Spring Boot实现qq邮箱验证码注册和登录验证功能

    Spring Boot实现qq邮箱验证码注册和登录验证功能

    这篇文章主要给大家介绍了关于Spring Boot实现qq邮箱验证码注册和登录验证功能的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • SpringBoot与velocity的结合的示例代码

    SpringBoot与velocity的结合的示例代码

    本篇文章主要介绍了SpringBoot与velocity的结合的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • 关于TreeMap自定义排序规则的两种方式

    关于TreeMap自定义排序规则的两种方式

    这篇文章主要介绍了关于TreeMap自定义排序规则的两种方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • springboot上传文件过大的500异常解决

    springboot上传文件过大的500异常解决

    这篇文章主要介绍了springboot上传文件过大的500异常解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • java的多线程用法编程总结

    java的多线程用法编程总结

    本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。
    2016-10-10
  • 使用spring框架中的组件发送邮件功能说明

    使用spring框架中的组件发送邮件功能说明

    Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。这篇文章主要介绍了使用spring框架中的组件发送邮件,需要的朋友可以参考下
    2017-11-11
  • SpringCloud中Zuul网关原理及其配置

    SpringCloud中Zuul网关原理及其配置

    Spring Cloud是一个基于Spring Boot实现的微服务应用开发工具,其中的Zuul网关可以实现负载均衡、路由转发、鉴权、限流等功能,本文将从Spring Cloud中Zuul网关的原理、使用场景和配置过程详细介绍,帮助大家更好地了解和应用Zuul网关,需要的朋友可以参考下
    2023-06-06

最新评论