java.util.concurrent简介

简介: java.util.concurrent简介

文章目录



java.util.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;
    }
}
相关文章
|
2天前
|
存储 JavaScript Java
Java 中的 String Pool 简介
本文介绍了 Java 中 String 对象及其存储机制 String Pool 的基本概念,包括字符串引用、构造方法中的内存分配、字符串文字与对象的区别、手工引用、垃圾清理、性能优化,以及 Java 9 中的压缩字符串特性。文章详细解析了 String 对象的初始化、内存使用及优化方法,帮助开发者更好地理解和使用 Java 中的字符串。
Java 中的 String Pool 简介
|
5月前
|
Oracle 安全 Java
Java语言简介及发展
Java语言简介及发展
|
6月前
|
Java 编译器 测试技术
Java基础16-Java注解简介和最佳实践(二)
Java基础16-Java注解简介和最佳实践(二)
47 4
|
7月前
|
SQL Java 程序员
Java 8中的Stream API:简介与实用案例
【5月更文挑战第23天】本文将深入探讨Java 8中的Stream API,这是一种能够极大提升Java程序员生产力的新特性。我们将从基础概念开始,然后通过一些实用的案例来展示如何使用Stream API进行数据处理和操作。无论你是Java的初学者还是经验丰富的开发者,本文都将为你提供有价值的信息。
|
6月前
|
前端开发 Java 关系型数据库
JavaWeb开发简介
JavaWeb开发简介
61 0
|
6月前
|
Java 调度
Java并发基础-线程简介(状态、常用方法)
Java并发基础-线程简介(状态、常用方法)
40 0
|
4月前
|
并行计算 Java 程序员
Java中的Lambda表达式和函数式编程简介
【8月更文挑战第1天】Lambda表达式,在Java 8中引入,为Java程序员提供了一种简洁、灵活的编写代码的方式。本文将通过实例介绍Lambda表达式及其在函数式编程中的应用,并展示如何利用这些特性简化代码和提高开发效率。
32 2
|
5月前
|
设计模式 测试技术 Python
《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
【7月更文挑战第10天】Page Object Model (POM)是Selenium自动化测试中的设计模式,用于提高代码的可读性和维护性。POM将每个页面表示为一个类,封装元素定位和交互操作,使得测试脚本与页面元素分离。当页面元素改变时,只需更新对应页面类,减少了脚本的重复工作和维护复杂度,有利于团队协作。POM通过创建页面对象,管理页面元素集合,将业务逻辑与元素定位解耦合,增强了代码的复用性。示例展示了不使用POM时,脚本直接混杂了元素定位和业务逻辑,而POM则能解决这一问题。
69 6
|
6月前
|
安全 Java 开发者
Java基础16-Java注解简介和最佳实践(一)
Java基础16-Java注解简介和最佳实践(一)
64 5
|
6月前
|
IDE Java 项目管理
Java入门——Intellij IDEA简介、使用IDEA开发程序、IDEA常用快捷键、IDEA其他操作
Java入门——Intellij IDEA简介、使用IDEA开发程序、IDEA常用快捷键、IDEA其他操作
97 3