92. 你说你精通Java并发,那给我讲讲JUC吧(三)

简介: 92. 你说你精通Java并发,那给我讲讲JUC吧(三)

92. 你说你精通Java并发,那给我讲讲JUC吧(三)


J.U.C - 其它组件(这部分还需要细致总结)

FutureTask

在介绍 Callable 时我们知道它可以有返回值,返回值通过 Future 进行封装。FutureTask 实现了 RunnableFuture 接口,该接口继承自 Runnable 和 Future 接口,这使得 FutureTask 既可以当做一个任务执行,也可以有返回值。

public class FutureTask<V> implements RunnableFuture<V>public interface RunnableFuture<V> extends Runnable, Future<V>

FutureTask 可用于异步获取执行结果或取消执行任务的场景。当一个计算任务需要执行很长时间,那么就可以用 FutureTask 来封装这个任务,主线程在完成自己的任务之后再去获取结果。

public class FutureTaskExample { 
    public static void main(String[] args) throws ExecutionException, InterruptedException {    
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {   
            @Override         
            public Integer call() throws Exception {              
                int result = 0;         
                for (int i = 0; i < 100; i++) {           
                    Thread.sleep(10);              
                    result += i;         
                }             
                return result;     
            }
        });   
        Thread computeThread = new Thread(futureTask);       
        computeThread.start(); 
        Thread otherThread = new Thread(() -> {      
            System.out.println("other task is running...");       
            try {       
                Thread.sleep(1000);    
            } catch (InterruptedException e) {             
                e.printStackTrace();         
            }     
        });      
        otherThread.start();       
        System.out.println(futureTask.get());   
    }
}

控制台输出结果为:

other task is running...
4950

BlockingQueue

java.util.concurrent.BlockingQueue 接口有以下阻塞队列的实现:

FIFO 队列 : LinkedBlockingQueue、ArrayBlockingQueue(固定长度)

优先级队列 : PriorityBlockingQueue 提供了阻塞的 take() 和 put() 方法:如果队列为空 take() 将阻塞,直到队列中有内容;如果队列为满 put() 将阻塞,直到队列有空闲位置。

使用 BlockingQueue 实现生产者消费者问题

public class ProductorConsumer {   
    private static BlockingQueue<String> quene = new ArrayBlockingQueue<>(5);    
    private static class Productor extends Thread{   
        @Override
        public void run() {   
            try {
                quene.put("product");  
            } catch (InterruptedException e) {    
                e.printStackTrace(); 
            }         
            System.out.println("productor...");    
        }    
    }   
    private static class Consumer extends Thread{    
        @Override  
        public void run() {     
            try {          
                String product = quene.take();         
            } catch (InterruptedException e) {     
                e.printStackTrace();            
            }            
            System.out.println("consumer...");    
        }  
    }    
    public static void main(String[] args) {  
        for(int i = 0; i < 2; i++){          
            Productor productor = new Productor();            
            productor.start();     
        }        
        for(int i = 0; i < 5; i++){        
            Consumer consumer = new Consumer();      
            consumer.start();   
        }        
        for(int i = 0; i < 3; i++){   
            Productor productor = new Productor();         
            productor.start();       
        }    
    }
}

控制台输出结果为(每次都不一样):

productor...
productor...
consumer...
consumer...
productor...
productor...
consumer...
consumer...
productor...
consumer...

ForkJoin

使用了**“分治”**的思想。

主要用于并行计算中,和 MapReduce 原理类似,都是把大的计算任务拆分成多个小任务并行计算。

import java.util.concurrent.RecursiveTask;
public class ForkJoinExample extends RecursiveTask<Integer> {   
    private final int threshold = 5;    
    private int first;    
    private int last;    
    public ForkJoinExample(int first, int last) {       
        this.first = first;        
        this.last = last;    
    }    
    @Override    
    protected Integer compute() {        
        int result = 0;        
        if (last - first <= threshold) {      
            // 任务足够小则直接计算           
            for (int i = first; i <= last; i++) {       
                result += i;            
      }        
        } else {    
            // 拆分成小任务            
            int middle = first + (last - first) / 2;            
            ForkJoinExample leftTask = new ForkJoinExample(first, middle);           
            ForkJoinExample rightTask = new ForkJoinExample(middle + 1, last);           
            leftTask.fork();            
            rightTask.fork();           
            result = leftTask.join() + rightTask.join();        
        }       
        return result;    
    }
}

窃取算法(工作窃密算法)

工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。

一个大任务分割为若干个互不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的队列里,并未每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应。比如线程1负责处理1队列里的任务,2线程负责2队列的。但是有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务待处理。干完活的线程与其等着,不如帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们可能会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务线程永远从双端队列的尾部拿任务执行。

优点:充分利用线程进行并行计算,减少线程间的竞争。

缺点:在某些情况下还是会存在竞争,比如双端队列里只有一个任务时。并且该算法会消耗更多的系统资源, 比如创建多个线程和多个双端队列。

在Java中,

可以使用LinkedBlockingDeque来实现工作窃取算法

JDK1.7引入的Fork/Join框架就是基于工作窃取算法

另外,jdk1.7中引入了一种新的线程池:WorkStealingPool。

参考:

https://blog.csdn.net/pange1991/article/details/80944797

https://blog.csdn.net/huzhiqiangcsdn/article/details/55251384

https://www.cnblogs.com/waterystone/p/4920797.html

目录
相关文章
|
3月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
25天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
2月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
1月前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
1月前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
51 2
|
2月前
|
Java
【编程进阶知识】揭秘Java多线程:并发与顺序编程的奥秘
本文介绍了Java多线程编程的基础,通过对比顺序执行和并发执行的方式,展示了如何使用`run`方法和`start`方法来控制线程的执行模式。文章通过具体示例详细解析了两者的异同及应用场景,帮助读者更好地理解和运用多线程技术。
32 1
|
3月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
3月前
|
Java API 容器
JAVA并发编程系列(10)Condition条件队列-并发协作者
本文通过一线大厂面试真题,模拟消费者-生产者的场景,通过简洁的代码演示,帮助读者快速理解并复用。文章还详细解释了Condition与Object.wait()、notify()的区别,并探讨了Condition的核心原理及其实现机制。
|
3月前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
192 6
【Java学习】多线程&JUC万字超详解
|
4月前
|
缓存 Java 调度
【Java 并发秘籍】线程池大作战:揭秘 JDK 中的线程池家族!
【8月更文挑战第24天】Java的并发库提供多种线程池以应对不同的多线程编程需求。本文通过实例介绍了四种主要线程池:固定大小线程池、可缓存线程池、单一线程线程池及定时任务线程池。固定大小线程池通过预设线程数管理任务队列;可缓存线程池能根据需要动态调整线程数量;单一线程线程池确保任务顺序执行;定时任务线程池支持周期性或延时任务调度。了解并正确选用这些线程池有助于提高程序效率和资源利用率。
60 2