一、摘要 在上篇文章中,我们介绍了Future相关的用法,使用它可以获取异步任务执行的返回值。 我们再次回顾一下Future相关的用法。 publicclassFutureTest{ publicstaticvoidmain(String[]args)throwsException{ longstartTime=System.currentTimeMillis(); //创建一个线程池 ExecutorServiceexecutor=Executors.newFixedThreadPool(1); //提交任务并获得Future的实例 Future<String>future=...

  f3qniBV6IkjY   2024年03月15日   104   0   0 Java

一、摘要 在前几篇线程系列文章中,我们介绍了线程池的相关技术,任务执行类只需要实现Runnable接口,然后交给线程池,就可以轻松的实现异步执行多个任务的目标,提升程序的执行效率,比如如下异步执行任务下载。 //创建一个线程池 ExecutorServiceexecutor=Executors.newFixedThreadPool(2); //提交任务 executor.submit(newRunnable(){ @Override publicvoidrun(){ //执行下载某文件任务 System.out.println("执行下载某文件任务"); } }); 而实际上Runnabl...

  f3qniBV6IkjY   2024年03月14日   189   0   0 Java

一、摘要 在之前的文章中,我们介绍了ReentrantLock、ReadWriteLock、CountDownLatch、CyclicBarrier、Semaphore、ThreadPoolExecutor等并发工具类的使用方式,它们在请求共享资源的时候,都能实现线程同步的效果。 在使用方式上稍有不同,有的是独占式,多个线程竞争时只有一个线程能执行方法,比如ReentrantLock等;有的是共享式,多个线程可以同时执行方法,比如:ReadWriteLock、CountDownLatch、Semaphore等,不同的实现争用共享资源的方式也不同。 如果仔细阅读源码,会发现它们都是基于Abstr...

  f3qniBV6IkjY   2024年03月13日   28   0   0 Java

一、简介 在之前的多线程系列文章中,我们陆陆续续的介绍了Thread线程类相关的知识和用法,其实在Thread类上还有一层ThreadGroup类,也就是线程组。 今天我们就一起来简单的聊聊线程组相关的知识和用法。 二、什么是线程组 线程组,简单来说就是多个线程的集合,它的出现主要是为了更方便的管理线程。 从结构角度看,线程组与线程之间其实是一个父子结构,一个线程组可以拥有几个线程,同时也可以拥有几个线程组。整个组织结构像一棵树一样,每个线程一定有一个线程组,线程组可能又有一个父线程组,追溯到根节点就是一个系统线程组。 线程组与线程之间的关系,可以用如下图来描述。 比如,我们通常创建的mai...

  f3qniBV6IkjY   2024年03月12日   76   0   0 Java

一、简介 在Java的java.util.concurrent包中,除了提供底层锁、并发同步等工具类以外,还提供了一组原子操作类,大多以Atomic开头,他们位于java.util.concurrent.atomic包下。 所谓原子类操作,顾名思义,就是这个操作要么全部执行成功,要么全部执行失败,是保证并发编程安全的重要一环。 相比通过synchronized和lock等方式实现的线程安全同步操作,原子类的实现机制则完全不同。它采用的是通过无锁(lock-free)的方式来实现线程安全(thread-safe)访问,底层原理主要基于CAS操作来实现。 某些业务场景下,通过原子类来操作,既可以实...

  f3qniBV6IkjY   2024年03月11日   117   0   0 Java

一、摘要 在前几篇文章中,我们讲到了线程、线程池、BlockingQueue等核心组件,其实JDK给开发者还提供了比synchronized更加高级的线程同步组件,比如CountDownLatch、CyclicBarrier、Semaphore、Exchanger等并发工具类。 下面我们一起来了解一下这些常用的并发工具类! 二、常用并发工具类 2.1、CountDownLatch CountDownLatch是JDK5之后加入的一种并发流程控制工具类,它允许一个或多个线程一直等待,直到其他线程运行完成后再执行。 它的工作原理主要是通过一个计数器来实现,初始化的时候需要指定线程的数量;每当一个线...

  f3qniBV6IkjY   2024年03月07日   125   0   0 Java

一、前言 虽然Java对线程的创建、中断、等待、通知、销毁、同步等功能提供了很多的支持,但是从操作系统角度来说,频繁的创建线程和销毁线程,其实是需要大量的时间和资源的。 例如,当有多个任务同时需要处理的时候,一个任务对应一个线程来执行,以此来提升任务的执行效率,模型图如下: 如果任务数非常少,这种模式倒问题不大,但是如果任务数非常的多,可能就会存在很大的问题: 1.线程数不可控:随着任务数的增多,线程数也会增多,这些线程都没办法进行统一管理 2.系统的开销很大:创建线程对系统来说开销很高,随着线程数也会增多,可能会出现系统资源紧张的问题,严重的情况系统可能直接死机 假如把很多任务让一组线...

  f3qniBV6IkjY   2024年03月06日   23   0   0 Java

一、摘要 在之前的文章中,我们介绍了生产者和消费者模型的最基本实现思路,相信大家对它已经有一个初步的认识。 在Java的并发包里面还有一个非常重要的接口:BlockingQueue。 BlockingQueue是一个阻塞队列,更为准确的解释是:BlockingQueue是一个基于阻塞机制实现的线程安全的队列。通过它也可以实现生产者和消费者模型,并且效率更高、安全可靠,相比之前介绍的生产者和消费者模型,它可以同时实现生产者和消费者并行运行。 那什么是阻塞队列呢? 简单的说,就是当参数在入队和出队时,通过加锁的方式来避免线程并发操作时导致的数据异常问题。 在Java中,能对线程并发执行进行加锁的...

  f3qniBV6IkjY   2024年03月05日   99   0   0 Java

一、摘要 在上一篇文章中,我们讲到了使用ReadWriteLock可以解决多线程同时读,但只有一个线程能写的问题。 如果继续深入的分析ReadWriteLock,从锁的角度分析,会发现它有一个潜在的问题:如果有线程正在读数据,写线程准备修改数据的时候,需要等待读线程释放锁后才能获取写锁,简单的说就是,读的过程中不允许写,这其实是一种悲观的读锁。 为了进一步的提升程序并发执行效率,Java8引入了一个新的读写锁:StampedLock。 与ReadWriteLock相比,StampedLock最大的改进点在于:在原先读写锁的基础上,新增了一种叫乐观读的模式。该模式并不会加锁,因此不会阻塞线程,程...

  f3qniBV6IkjY   2024年03月04日   29   0   0 Java

一、简介 在Java多线程编程中,还有一个非常重要的设计模式,它就是:生产者和消费者模型。 这种模型可以充分发挥cpu的多线程特性,通过一些平衡手段能有效的提升系统整体处理数据的速度,减轻系统负载,提高程序的效率和稳定性,同时实现模块之间的解耦。 那什么是生产者和消费者模型呢? 简单的说,生产者和消费者之间不直接进行交互,而是通过一个缓冲区来进行交互,生产者负责生成数据,然后存入缓冲区;消费者则负责处理数据,从缓冲区获取。 大致流程图如下: 对于最简单的生产者和消费者模型,总结下来,大概有以下几个特点: 缓冲区为空的时候,消费者不能消费,会进入休眠状态,直到有新数据进入缓冲区,再次被唤醒 ...

  f3qniBV6IkjY   2024年03月04日   63   0   0 Java

一、摘要 在上篇文章中,我们讲到ReentrantLock可以保证了只有一个线程能执行加锁的代码。 但是有些时候,这种保护显的有点过头,比如下面这个方法,它仅仅就是只读取数据,不修改数据,它实际上允许多个线程同时调用的。 publicclassCounter{ privatefinalLocklock=newReentrantLock(); privateintcount; publicintget(){ //加锁 lock.lock(); try{ returncount; }finally{ //释放锁 lock.unlock(); } } } 站在程序性能的角度,实际上我们想要的...

  f3qniBV6IkjY   2024年02月27日   93   0   0 Java

一、简介 在上一篇文章中,我们介绍了ReentrantLock类的一些基本用法,今天我们重点来介绍一下ReentrantLock其它的常用方法,以便对ReentrantLock类的使用有更深入的理解。 二、常用方法介绍 2.1、构造方法 ReentrantLock类有两个构造方法,核心源码内容如下: / 默认创建非公平锁 / publicReentrantLock(){ sync=newNonfairSync(); } / fair为true表示是公平锁,fair为false表示是非公平锁 / publicReentrantLock(booleanfair){ sync=fair?newFa...

  f3qniBV6IkjY   2024年02月26日   93   0   0 Java

一、简介 在Javaweb项目中,想必很多的同学对ThreadLocal这个类并不陌生,它最常用的应用场景就是用来做对象的跨层传递,避免多次传递,打破层次之间的约束。 比如下面这个HttpServletRequest参数传递的简单例子! publicclassRequestLocal{ / 线程本地变量 / privatestaticThreadLocal<HttpServletRequest>local=newThreadLocal<>(); / 存储请求对象 @paramrequest / publicstaticvoidset(HttpServletReque...

  f3qniBV6IkjY   2024年02月23日   99   0   0 Java

一、简介 在之前的线程系列文章中,我们介绍到了使用synchronized关键字可以实现线程同步安全的效果,以及采用wait()、notify()和notifyAll()方法,可以实现多个线程之间的通信协调,基本可以满足并发编程的需求。 但是采用synchronized进行加锁,这种锁一般都比较重,里面的实现机制也非常复杂,同时获取锁时必须一直等待,没有额外的尝试机制,如果编程不当,可能就容易发生死锁现象。 从JDK1.5开始,引入了一个高级的处理并发的java.util.concurrent包,它提供了大量更高级的并发功能,能大大的简化多线程程序的编写。 比如我们今天要介绍的java.uti...

  f3qniBV6IkjY   2024年02月23日   82   0   0 Java

一、简介 在之前的线程系列文章中,我们介绍了synchronized和volatile关键字,使用它能解决线程同步的问题,但是它们无法解决线程之间协调和通信的问题。 举个简单的例子,比如线程A负责将int型变量i值累加操作到10000,然后通知线程B负责把结果打印出来。 这个怎么实现呢?其中一个最简单的办法就是,线程B不断的通过轮询方式while(i10000)检查是否满足条件,这样就可以实现了。 虽然这种方式可以实现需求,但是也带来了另一个问题:线程B中的while()操作不会释放CPU资源,会导致CPU一直在这个方法上做判断操作,极大的浪费CPU资源。 我们知道CPU资源是非常非常昂贵的,...

  f3qniBV6IkjY   2024年02月22日   76   0   0 Java

一、简介 在上篇文章中,我们介绍到在多线程环境下,如果编程不当,可能会出现程序运行结果混乱的问题。 出现这个原因主要是,JMM中主内存和线程工作内存的数据不一致,以及多个线程执行时无序,共同导致的结果。 同时也提到引入synchronized同步锁,可以保证线程同步,让多个线程依次排队执行被synchronized修饰的方法或者方法块,使程序的运行结果与预期一致。 不可否认,采用synchronized同步锁确实可以保证线程安全,但是它对服务性能的消耗也很大,synchronized是一个独占式的同步锁,比如当多个线程尝试获取锁时,其中一个线程获取到锁之后,未获取到锁的线程会不断的尝试获取锁...

  f3qniBV6IkjY   2024年02月21日   47   0   0 Java

一、简介 在很多场景下,我们经常听到采用多线程编程,能显著的提升程序的执行效率。例如执行大批量数据的插入操作,采用单线程编程进行插入可能需要30分钟,采用多线程编程进行插入可能只需要5分钟就够了。 既然多线程编程技术如此厉害,那什么是多线程呢? 在介绍多线程之前,我们还得先讲讲进程和线程的概念。 二、进程和线程 2.1、什么是进程? 从计算机角度来讲,进程是操作系统中的基本执行单元,也是操作系统进行资源分配和调度的基本单位,并且进程之间相互独立,互不干扰。 例如,我们windows电脑中的Chrome浏览器是一个进程、WeChat也是一个进程,正在操作系统中运行的.exe都可以理解为一个进程。...

  f3qniBV6IkjY   2024年02月19日   84   0   0 Java

一、简介 在之前的文章中,我们简单的介绍了线程诞生的意义和基本概念,采用多线程的编程方式,能充分利用CPU资源,显著的提升程序的执行效率。 其中java.lang.Thread是Java实现多线程编程最核心的类,学习Thread类中的方法,是学习多线程的第一步。 下面我们就一起来看看,创建线程的几种方式以及Thread类中的常用方法。 二、创建线程的方式 在JDK1.8版本中,创建线程总共有四种方式: 继承Thread类 实现Runnable接口 使用Callable和Future创建线程 使用JDK8的Lambda创建线程 2.1、通过继承Thread创建线程 通过继承Thread类来创...

  f3qniBV6IkjY   2024年02月19日   140   0   0 Java
关注 更多

空空如也 ~ ~

粉丝 更多

空空如也 ~ ~