返回顶部
首页 > 资讯 > 后端开发 > Python >带你快速搞定java并发库
  • 631
分享到

带你快速搞定java并发库

2024-04-02 19:04:59 631人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录一、总览二、Executor总览三、继承结构四、怎么保证只有一个线程五、怎么保证时间可以定时执行六、使用总结一、总览 计算机程序 = 数据 + 算法。 并发编程的一切根本原因是为

一、总览

计算机程序 = 数据 + 算法。

并发编程的一切根本原因是为了保证数据的正确性,线程的效率性。

java并发库共分为四个大的部分,如下图

Executor 和 future 是为了保证线程的效率性

Lock 和数据结构 是为了维持数据的一致性。

Java并发编程的时候,思考顺序为,

对自己的数据要么加。要么使用提供的数据结构,保证数据的安全

调度线程的时候使用Executor更好的调度。

二、Executor总览

Executor 提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。

相当于manager,老板让manager去执行一件任务,具体的是谁执行,什么时候执行,就不管了。

看上图的继承关系,介绍几个

内置的线程池基本上都在这里

newScheduledThreadPool 定时执行的线程池

newCachedThreadPool 缓存使用过的线程

newFixedThreadPool 固定数量的线程池

newWorkStealingPool 将大任务分解为小任务的线程池

三、继承结构

构造函数

包含一个定时的service


public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}
static class DelegatedScheduledExecutorService
        extends DelegatedExecutorService
        implements ScheduledExecutorService {
    private final ScheduledExecutorService e;
    DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
        super(executor);
        e = executor;
    }

四、怎么保证只有一个线程

定时执行的时候调用这个方法,调用过程如下,注意看其中的注释,由上往下的调用顺序


public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    if (delay <= 0)
        throw new IllegalArgumentException();
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(-delay));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    //  延迟执行
    delayedExecute(t);
    return t;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
    if (isshutdown())
        reject(task);
    else {
        // 加入任务队列
        super.getQueue().add(task);
        if (isShutdown() &&
            !canRunInCurrentRunState(task.isPeriodic()) &&
            remove(task))
            task.cancel(false);
        else
            // 确保执行
            ensurePrestart();
    }
}
// 如果worker数量小于corePoolSize,创建新的线程,其他情况不处理
void ensurePrestart() {
    int wc = workerCountOf(ctl.get());
    if (wc < corePoolSize)
        addWorker(null, true);
    else if (wc == 0)
        addWorker(null, false);
}

五、怎么保证时间可以定时执行


public ScheduledFuture<?> schedule(Runnable command,
                                   long delay,
                                   TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    RunnableScheduledFuture<?> t = decorateTask(command,
        new ScheduledFutureTask<Void>(command, null,
                                      triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}

在每次执行的时候会把下一次执行的时间放进任务中


private long triggerTime(long delay, TimeUnit unit) {
    return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}

long triggerTime(long delay) {
    return now() +
        ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}

FutureTask 定时是通过LockSupport.parkNanos(this, nanos);LockSupport.park(this);


private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    Waitnode q = null;
    boolean queued = false;
    for (;;) {
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }
        int s = state;
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        else if (q == null)
            q = new WaitNode();
        else if (!queued)
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
        else if (timed) {
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q);
                return state;
            }
            //注意这里
            LockSupport.parkNanos(this, nanos);
        }
        else //注意这里
            LockSupport.park(this);
    }
}

总结:Executor是通过将任务放在队列中,生成的futureTask。然后将生成的任务在队列中排序,将时间最近的需要出发的任务做检查。如果时间不到,就阻塞线程到下次出发时间。

注意:newSingleThreadScheduledExecutor只会有一个线程,不管你提交多少任务,这些任务会顺序执行,如果发生异常会取消下面的任务,线程池也不会关闭,注意捕捉异常

六、使用


ScheduledExecutorService single = Executors.newSingleThreadScheduledExecutor();
Runnable runnable1 = () -> {
    try {
        Thread.sleep(4000);
        System.out.println("11111111111111");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};
Runnable runnable2 = () -> {
    try {
        Thread.sleep(4000);
        System.out.println("222");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};
single.scheduleWithFixedDelay(runnable1,0,1, TimeUnit.SECONDS);
single.scheduleWithFixedDelay(runnable2,0,2, TimeUnit.SECONDS);

11111111111111 222 11111111111111 222 11111111111111

项目中要注意关闭线程池


actionService = Executors.newSingleThreadScheduledExecutor();
        actionService.scheduleWithFixedDelay(() -> {
            try {
                Thread.currentThread().setName("robotActionService");
                Integer robotId = robotQueue.poll();
                if (robotId == null) {
                    //    关闭线程池
                    actionService.shutdown();
                } else {
                    int aiLv = robots.get(robotId);
                    if (actionQueueMap.containsKey(aiLv)) {
                        ActionQueue actionQueue = actionQueueMap.get(aiLv);
                        actionQueue.doAction(robotId);
                    }
                }
            } catch (Exception e) {
                //    捕捉异常
                LOG.error("",e);
            }
        }, 1, 1, TimeUnit.SECONDS);

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: 带你快速搞定java并发库

本文链接: https://lsjlt.com/news/130527.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 带你快速搞定java并发库
    目录一、总览二、Executor总览三、继承结构四、怎么保证只有一个线程五、怎么保证时间可以定时执行六、使用总结一、总览 计算机程序 = 数据 + 算法。 并发编程的一切根本原因是为...
    99+
    2024-04-02
  • 带你快速搞定java IO
    目录一、IO底层是怎么回事?二、梳理类的结构三、IO类大点兵四、来波实例展示1、访问操作文件(FileInputStream/FileReader ,FileOutputStream...
    99+
    2024-04-02
  • 带你快速搞定java数组
    目录1、数组的定义2、array 遍历3、List和array 之间的转换1、数组转list2、list 转数组3、Arrays工具类4、可能遇到的问题总结1、数组的定义 ...
    99+
    2024-04-02
  • 带你快速搞定java多线程
    目录1、什么是线程2、线程的状态3、怎么通俗理解进程,线程?4、线程和进程的区别5、什么是线程安全6、如何创建线程总结:1、什么是线程 线程是操作系统调度的最小单元,也叫轻量级进程。...
    99+
    2024-04-02
  • 带你快速搞定java多线程(2)
    目录1、Future的类图结构,从整体上看下Future的结构2、future的使用,说的再多都么什么用,来个例子悄悄怎么用的。3、通俗理解4、原理5、总结1、Future的类图结构...
    99+
    2024-04-02
  • 带你快速搞定java多线程(3)
    目录一、锁的概念二、synchronized 的使用方式三、synchronized 的实现原理列小结四、线程池是什么五、为什么要用线程池?六、看下类图,从整体上理解下七、线程池的创...
    99+
    2024-04-02
  • 带你快速搞定java多线程(4)
    目录1、AQS 是什么?2、AQS 模型3、AQS state4、AQS 两种资源共享方式:5、模板方式实现自定义6、锁的分类:公平锁和非公平锁,乐观锁和悲观锁7、CAS8、总结1、...
    99+
    2024-04-02
  • 带你快速搞定java多线程(5)
    目录1、介绍2、countdownlantch的用法。3、如何利用AQS 实现 CountDownLatch4、总结1、介绍 CountDownLantch 倒数计时器,一个同步辅助...
    99+
    2024-04-02
  • 带你快速搞定Mysql优化
    目录1、查询语句的执行顺序2、数据类型的选择3、索引优化主键索引多列索引4、查询性能优化1、查询的生命周期2、SELECT语句尽量指明查询字段名称3、小表驱动大表总结1、查询...
    99+
    2024-04-02
  • 一篇文章带你搞定JAVA Maven
    目录1、maven是什么,为什么存在?项目结构是什么样子,怎么定位jar2、Idea 的操作1.新建maven项目2.配置仓库3.添加依赖,添加fastjson的依赖4.打包项目3、...
    99+
    2024-04-02
  • 一篇文章带你搞定JAVA泛型
    目录1、泛型的概念2、泛型的使用3、泛型原理,泛型擦除3.1 IDEA 查看字节码3.2 泛型擦除原理4、?和 T 的区别5、super extends6、注意点1、静态方法无法访问...
    99+
    2024-04-02
  • 一篇文章带你搞定JAVA注解
    目录1、注解是什么2、jdk支持的注解有哪些2.1 三种常用的注解:2.2 元注解3、注解实例1、自定义注解2、在对应的方法上增加注解3、在项目启动的时候检查注解的枚举4、总结1、注...
    99+
    2024-04-02
  • 一篇文章带你搞定JAVA反射
    目录1、反射的概念1、概念2、获取字节码文件对象的方式2.1 元数据的概念2.2 获取class对象的方式1、访问权限2、获取方法2.1 访问静态方法2.2 访问类方法 3...
    99+
    2024-04-02
  • 手把手带你用java搞定汉诺塔
    目录什么是汉诺塔问题剖析n=1n=2n=3小结Java代码实现代码讲解move函数hanoiTower函数附:C语言实现汉诺塔总结什么是汉诺塔 汉诺塔问题是一个经典的问题。汉诺塔(H...
    99+
    2024-04-02
  • 10分钟搞定Java并发队列
    目录前言并发队列ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueueDelayQueueSynchronousQueu...
    99+
    2024-04-02
  • 一篇文章带你搞定JAVA内存泄漏
    目录1、什么是内存泄漏2、内存泄漏的原因3、内存泄漏有哪些情况3.1 代码中没有及时释放,导致内存无法回收。3.2 资源未关闭造成的内存泄漏3.3 全局缓存持有的对象不使用的时候没有...
    99+
    2024-04-02
  • 手把手带你用java搞定青蛙跳台阶
    目录问题描述问题剖析n=1n=2n=3n=4小结Java代码示例附:C语言实现青蛙跳台阶总结问题描述 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶...
    99+
    2024-04-02
  • 一文带你搞懂Java定时器Timer的使用
    目录一、定时器是什么二、自定义定时器一、定时器是什么 定时器类似于我们生活中的闹钟,可以设定一个时间来提醒我们。 而定时器是指定一个时间去执行一个任务,让程序去代替人工准时操作。 标...
    99+
    2023-01-09
    Java定时器Timer使用 Java定时器Timer Java定时器 Java Timer
  • 一篇文章带你搞懂Java restful 接口开发
    目录1、RESTful 简介a>资源b>资源的表述c>状态转移2、RESTful 的实现3、HiddenHttpMethodFilter4、RESTful 案例4....
    99+
    2024-04-02
  • Python 带你快速上手 Apache APISIX 插件开发
    目录一、了解:项目架构二、安装:部署测试1.下载安装PythonRunner2.配置PythonRunner3.启动PythonRunner4.测试PythonRunner三、实践:...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作