栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

Java(二十六)-- Java并发编程(四)

Java 更新时间:发布时间: 百科书网 趣学号

目录

ForkJoin 框架

ForkJoin 框架,核心是两个类

Volatile 关键字

线程池 workQueue

目录

ForkJoin 框架

ForkJoin 框架,核心是两个类

Volatile 关键字

线程池 workQueue

递归

什么是递归?

递归需要满足 3 要素


ForkJoin 框架

        ForkJoin 是 JDK 1.7 后发布的多线程并发处理框架,功能上和 JUC 类似,JUC 更多时候是使用单个类完成操作,ForkJoin 使用多个类同时完成某项工作,处理上比 JUC 更加丰富,实际开发中使用的场景并不是很多,互联网公司真正有高并发需求的情况才会使用,面试时候会加分

        本质上是对线程池的一种的补充,对线程池功能的一种扩展,基于线程池的,它的核心思想就是将一个大型的任务拆分成很多个小任务,分别执行,最终将小任务的结果进行汇总,生成最终的结果。

         

        本质就是把一个线程的任务拆分成多个小任务,然后由多个线程并发执行,最终将结果进行汇总。

        比如 A B 两个线程同时还执行,A 的任务比较多,B 的任务相对较少,B 先执行完毕,这时候 B 去帮助 A 完成任务(将 A 的一部分任务拿过来替 A 执行,执行完毕之后再把结果进行汇总),从而提高效率。

工作窃取

        

ForkJoin 框架,核心是两个类
  • ForkJoinTask (描述任务)

  • ForkJoinPool(线程池)提供多线程并发工作窃取

        使用 ForkJoinTask 最重要的就是要搞清楚如何拆分任务,这里用的是递归思想。

                1、需要创建一个 ForkJoinTask 任务,ForkJoinTask 是一个抽象类,不能直接创建 ForkJoinTask 的实例化对象,开发者需要自定义一个类,继承 ForkJoinTask 的子类 RecursiveTask ,Recursive 就是递归的意思,该类就提供了实现递归的功能。

        

import java.util.concurrent.RecursiveTask;
​

public class ForkJoinDemo extends RecursiveTask {
​
    private Long start;
    private Long end;
    private Long temp = 100_0000L;
​
    public ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }
​
    @Override
    protected Long compute() {
        if((end-start) 
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
​
public class Test {
    public static void main(String[] args) {
        Long startTime = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask task = new ForkJoinDemo(0L,10_0000_0000L);
        forkJoinPool.execute(task);
        Long sum = 0L;
        try {
            sum = task.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Long endTime = System.currentTimeMillis();
        System.out.println(sum+",供耗时"+(endTime-startTime));
    }
}

Volatile 关键字

         

        Volatile 是 JVM 提供的轻量级同步机制,可见性,主内存对线程可见。

        一个线程执行完任务之后,还会把变量存回到主内存中,并且从主内存中读取当前最新的值,如果是一个空的任务,则不会重新读取主内存中的值

import java.util.concurrent.TimeUnit;
​
public class Test {
    private static int num = 0;
​
    public static void main(String[] args) {
        
        new Thread(()->{
            while(num == 0){
                System.out.println("---Thread---");
            }
        }).start();
​
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        num = 1;
        System.out.println(num);
    }
}
import java.util.concurrent.TimeUnit;
​
public class Test {
    private static volatile int num = 0;
​
    public static void main(String[] args) {
        
        new Thread(()->{
            while(num == 0){
                
            }
        }).start();
​
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        num = 1;
        System.out.println(num);
    }
}

线程池 workQueue

一个阻塞队列,用来存储等待执行的任务,常用的阻塞队列有以下几种:

  • ArrayBlockingQueue:基于数组的先进先出队列,创建时必须指定大小。

  • LinkedBlockingQueue:基于链表的先进先出队列,创建时可以不指定大小,默认值时 Integer.MAX_VALUE。

  • SynchronousQueue:它不会保存提交的任务,而是直接新建一个线程来执行新来的任务。

  • PriorityBlockingQueue:具有优先级的阻塞队列。

递归

        二叉树遍历,深度优先搜索等。

什么是递归?

        常规的定义:编程语言中,函数 func 直接或者间接调用函数本身,则该函数称为递归函数。

         

        问前排人是第几排 -> 函数

        所有的递归问题都可以用递推公式来表示,所以要用递归解决问题,关键就是先找到递推公式。

f(n) = f(n-1)+1

f(1) = 1

        f(n) 表示你当前是第几排,f(n-1) 前面一排所在的排数,f(1) = 1 表示第一排的人知道自己是第一排。

int f(int n){
    if(n == 1) return 1;
    return f(n-1)+1;
}

递归需要满足 3 要素

        1、一个父问题可以拆分成若干个子问题,并且若干子问题的结果汇总起来就是父问题的答案。

        2、父问题和子问题,解题思路必须完全一致,只是数据规模不同。

        3、存在终止条件。

        问题在不断拆分的同时,一定要在某个节点终止拆分,得到一个明确的答案。

        问题:假设有 n 个台阶,每次可以跨 1 个台阶或者 2 个台阶,请问走完这 n 个台阶一共有多少种走法?

                1、假设有 1 个台阶,一共有(1) 种走法

                2、假设有 2 个台阶,一共有 2 种走法 【1,1】【2】

                3、假设有 3 个台阶,一共有()种走法?【1,1,1】【1,2】【2,1】

                ......

                可以根据第一步的走法进行分类

                第一类是第一步走了 1 个台阶

                第二类是第一步走了 2 个台阶

                所以 n 个台阶的走法就等于先走 1 个台阶后,n-1 个台阶的走法+先走 2 个台阶后,n-2 个台阶的走法。

f(n) = f(n-1)+f(n-2)

                f(1) = 1,能否作为终止条件?

                n = 2,f(2) = f(1)+f(0),如果终止条件只有一个 f(1) = 1,f(2) 就无法求解, 因为 f(0) 的值无法确定,

                把 f(2) = 2 作为一个终止条件

                终止条件有两个:

                        f(1) = 1;

                        f(2) = 2;

                        n = 3,f(3) = f(2)+f(1) = 3

                        n = 4,f(4) = f(3)+f(2) = 3 + 2 = 5

        递推公式

f(1) = 1;

f(2) = 2;

f(n) = f(n-1)+f(n-2);

        推导出递归代码

int f(int n){
    if(n == 1) return 1;
    if(n == 2) return 2;
    return f(n-1) + f(n-2);
}
public class Test {
    public static void main(String[] args) {
        for (int i = 1; i <= 30; i++) {
            System.out.println(i+"个台阶共有"+f(i)+"种走法");
        }
    }
​
    public static int f(int n){
        if(n == 1) return 1;
        if(n == 2) return 2;
        return f(n-1) + f(n-2);
    }
}
public class Test2 {
    public static void main(String[] args) {
        int d = f(10);
        System.out.println("d:"+d);
    }
​
    public static int f(int n){
        if(n == 1){
            System.out.println("m:"+n);
            return 1;
        }else{
            System.out.println("n:"+n);
            //n=4
            int c = f(n-1)+1;
            System.out.println("c:"+c);
            return c;
        }
    }
}

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/956699.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号