【Java小实验】【Java并发】使用线程池按行并发取二维数组最大值

2023-11-11

使用线程池按行并发取二维数组最大值

快手后端二面问题,由于网上直接搜竟然没有搜出来,自己写了一下

生成二维数组

生成二维数组的公共类


class RandomArray{
    public static double[][] getDoubleArray(int row, int col){
        double[][] array = new double[row][col];
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                array[i][j] = Math.random() * (i * 10L + 1);
            }
        }
        return array;
    }

    public static long[][] getLongArray(int row, int col){
        long[][] array = new long[row][col];
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                array[i][j] = (long)(Math.random() * (i * 10L + 1));
            }
        }
        return array;
    }
}

使用Callable实现线程

主要是实现下可返回值的线程,即通过Future.get()获取线程返回值。

import java.util.*;
import java.util.concurrent.*;

class ArrayMax implements Callable<Double> {
    private double[] array;
    private int ind;
    private double max = Double.MIN_VALUE;

    public ArrayMax(double[] array, int ind){
        this.array = array;
        this.ind = ind;
    }

    @Override
    public Double call() throws Exception{
        for(int i=0;i<array.length;i++){
            max = Math.max(max, array[i]);
        }
        // 只能这样来模拟执行时间不同
        // Thread.sleep((long) (Math.random() * 1000));
        System.out.println(Thread.currentThread().getName() + " of task " + ind + " max value: " + max);
        return max;
    }

    public double getMax(){
        return max;
    }

}

public class ArrayMaxTest {
    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            20,
            40,
            60 * 60,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(5000),
            new ThreadPoolExecutor.CallerRunsPolicy());

    private static Double max = Double.MIN_VALUE;

    private static int row, col;

    private static double[][] array;

    private static void unsafeMaintainMax(Double input){
        // max = Math.max(max, input);
        if(input > max) {
            max = input;
        }
    }

    private static void useThreadPool(){
        for(int i=0;i<row;i++){
            try{
                ArrayMax arrayMax = new ArrayMax(array[i], i);
                Future f = threadPoolExecutor.submit(arrayMax);
                // System.out.println("Thread " + i + " : " + f.get());
                // TODO : 猜测由于等待执行完还是按顺序,所以这个其实是安全的!!!
                unsafeMaintainMax((Double) f.get());
            } catch (Exception exception){
                System.out.println(exception);
            }
        }
        threadPoolExecutor.shutdown();
    }

    private static void useThreadPool2() throws ExecutionException, InterruptedException {
        List<Future> futureList = new ArrayList<>();
        Map<Integer, Future> futureMap = new HashMap<>();
        Set<Future> futureSet = new HashSet<>();
        for(int i=0;i<row;i++){
            try{
                ArrayMax arrayMax = new ArrayMax(array[i], i);
                Future f = threadPoolExecutor.submit(arrayMax);
                // System.out.println("Thread " + i + " : " + f.get());
                // futureList.add(f);
                // futureMap.put(i, f);
                futureSet.add(f);
            } catch (Exception exception){
                System.out.println(exception);
            }
        }

        // XXX:由于.get 方法是阻塞方法,(不论线程有没有sleep)直接遍历 这些线程 都是按顺序执行的
        // Thread.sleep(5000);
        // for(Future f : futureList){
        //     // Future.get 是个阻塞方法。会阻塞当前线程(主线程),要配合.isDone函数
        //     unsafeMaintainMax((Double) f.get());
        // }

        // 采用轮询遍历,此时这些线程才不是顺序执行了
        while(!futureSet.isEmpty()){
            List<Future> wait2Remove = new ArrayList<>();
            for(Future f : futureSet){
                if(f.isDone()){
                    // 由于是主线程进行取最大值,所以不论怎样都是安全的
                    unsafeMaintainMax((Double) f.get());
                    // futureSet.remove(f);
                    wait2Remove.add(f);
                }
            }
            // 要滞后删除,不能直接删除,否则会报错
            for(Future f : wait2Remove) {
                futureSet.remove(f);
            }
        }

        // while(!futureMap.isEmpty()){
        //     for(Map.Entry<Integer, Future> entry : futureMap.entrySet()){
        //         // System.out.print(entry.getKey() + " ");
        //         if(entry.getValue().isDone()){
        //             unsafeMaintainMax((Double) entry.getValue().get());
        //             futureMap.remove(entry.getKey());
        //             // System.out.println();
        //         }
        //     }
        // }

        threadPoolExecutor.shutdown();
        threadPoolExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
    }

    private static void useNormal(){
        Double submax = Double.MIN_VALUE;
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                submax = Math.max(submax, array[i][j]);
            }
        }
        unsafeMaintainMax(submax);
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        row = 400;
        col = 2000;
        long startTime = 0, endTime = 0;
        array = RandomArray.getDoubleArray(row, col);


        startTime = System.currentTimeMillis();

        useThreadPool2();
        // useNormal();

        System.out.println("unsafe Max : " + max);

        endTime = System.currentTimeMillis();
        System.out.println("开始时间:" + startTime +
                "\n结束时间:" + endTime +
                "\n用时:" + (endTime - startTime));
    }
}

这里注意要先把线程都运行起来再使用Future.get()获取返回值,否则运行马上获取则是顺序执行的,那么就没有意义了,这就还要写个自旋遍历并配合Future.isDone()方法来并行获取结果。后期可以考虑使用CountDownLatch获取结果。

使用Runnable获取线程

使用单例模式维护最大值。

import java.util.concurrent.*;


public class ArrayMaxTest2 implements Runnable {
    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            20,
            40,
            60 * 60,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(5000),
            new ThreadPoolExecutor.CallerRunsPolicy());

    private double[] array;
    private double max = Double.MIN_VALUE;

    private int ind;

    public ArrayMaxTest2(double[] array, int ind){
        this.array = array;
        this.ind = ind;
    }

    @Override
    public void run(){
        for(int i=0;i<array.length;i++){
            max = Math.max(max, array[i]);
        }
        System.out.println(Thread.currentThread().getName() + " of task " + ind + " max value: " + max);
        unsafeMaintainMax(max);
        // dclMainTainMax(max);
    }

    /

    private static Double ans = Double.MIN_VALUE;

    private static void unsafeMaintainMax(Double input){
        ans = Math.max(ans, input);
    }

    private static Double dclAns = Double.MIN_VALUE;

    private static void dclMainTainMax(Double input){
        synchronized (dclAns){
            dclAns = Math.max(dclAns, input);
        }
    }

    public static void main(String[] args){
        int row = 400, col = 2000;
        long startTime = 0, endTime = 0;
        double[][] twoDimArray = RandomArray.getDoubleArray(row, col);

        startTime = System.currentTimeMillis();
        for(int i=0;i<row;i++){
            try{
                ArrayMaxTest2 arrayMax = new ArrayMaxTest2(twoDimArray[i], i);
                threadPoolExecutor.execute(arrayMax);
            } catch (Exception exception){
                System.out.println(exception);
            }
        }
        threadPoolExecutor.shutdown();  // 阻止新来任务的提交

        // 这样前面的线程还没有执行完
        // System.out.println("unsafe Max : " + ans);
        // System.out.println("dcl Max : " + dclAns);
        // endTime = System.currentTimeMillis();
        // System.out.println("开始时间:" + startTime + "\n结束时间:" + endTime + "\n用时:" + (endTime - startTime));

        try {
            // 等待所有线程执行完
            threadPoolExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
            // TODO:还可以使用 CountDownLatch

            System.out.println("unsafe Max : " + ans);
            System.out.println("dcl Max : " + dclAns);
            endTime = System.currentTimeMillis();
            System.out.println("开始时间:" + startTime + "\n结束时间:" + endTime + "\n用时:" + (endTime - startTime));
        } catch (InterruptedException interruptedException){
            interruptedException.printStackTrace();
        }
    }
}

这里也可以发现,如果使用单例模式,不使用sychronizedvolatile同步,确实会出现问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Java小实验】【Java并发】使用线程池按行并发取二维数组最大值 的相关文章

  • 从文本文件中读取阿拉伯字符

    我完成了一个项目 在该项目中我读取了用记事本编写的文本文件 我的文本文件中的字符是阿拉伯语 文件编码类型是UTF 8 当在 Netbeans 7 0 1 中启动我的项目时 一切似乎都正常 但是当我将项目构建为 jar 文件时 字符以这种方式
  • 将 MouseListener 添加到面板

    我正在尝试将鼠标操作添加到我的面板中 这就是程序应该做的事情 编写一个程序 允许用户通过按三下鼠标来指定一个三角形 第一次按下鼠标后 画一个小点 第二次按下鼠标后 绘制一条连接前两个点的线 第三次按下鼠标后 绘制整个三角形 第四次按下鼠标会
  • 如何作为应用程序发布到页面?

    所以 我有一个应用程序 Facebook 应用程序实体 并且我有一个页面 我想使用应用程序通过java代码 通过restfb或任何其他建议 发布到页面 看起来我错过了页面授予应用程序发布权限的阶段 不知道该怎么做 谢谢你们 乌里 您只能 作
  • 从 Spring MVC XML 文件转移到 javaconfig。我真的对我的数据库 XML 文件感到困惑

    我从 Spring MVC XML 文件转移到 javaconfig 我真的对我的数据库 XML 文件感到困惑 我不知道如何让 Hibernate4 工作以及我的 JBoss JNDI 数据源工作 有人可以告诉我如何使 javaconfig
  • 我需要在 JFileChooser(打开模式)中显示不带扩展名的文件名。如何?

    我在打开模式下使用 JFileChooser 我需要显示不带扩展名的 文件名 字段 如何 我知道文件视图 它删除文件系统文件中的扩展名 但将所选文件中的扩展名保留在 文件名 字段中解释 http saveimg ru show image
  • 记录共享和映射的诊断上下文

    据我所知 其他人做了什么来解决 Commons Logging 项目 针对 NET 和 Java 不支持映射或嵌套诊断上下文这一事实 执行摘要 我们选择直接使用实现者日志框架 在我们的例子中为 log4j 长答案 您是否需要一个抽象日志框架
  • 在java中将字符串日期转换为美国格式

    我有下面的代码 其中日期为字符串类型 我必须将其设置为美国格式 所以下面我已经展示了它 private static final SimpleDateFormat usOutputDate new SimpleDateFormat MM d
  • 在grails控制器中识别ajax请求或浏览器请求

    我正在开发一个使用大量ajax的grails应用程序 如果请求是ajax调用 那么它应该给出响应 这部分正在工作 但是如果我在浏览器中输入URL 它应该带我到主页 索引页面而不是请求的页面 下面是ajax调用的示例gsp代码
  • java setFullScreenWindow 在 Mac 中隐藏登录对话框

    我使用的是全屏窗口 类似于屏幕保护程序 使用这里的方法 GraphicsEnvironment getLocalGraphicsEnvironment getDefaultScreenDevice setFullScreenWindow t
  • 插入时的 iBatis 判别器

    我有一个抽象类Example以及与之相伴的具体子类 我使用鉴别器来提取数据out数据库的 像这样
  • 在带有 Protocol Buffers 的项目中使用 Proguard 有什么特点?

    我有一个使用 Google Protocol Buffers 的项目 一旦我尝试用 ProGuard 对其进行混淆 似乎 protobuf 会导致问题 我将所有自己的类打包成mybuildedclasses jar 谷歌代码被打包成prot
  • JUNIT 测试 void 方法

    我有一个充满 void 方法的 java 类 我想进行一些单元测试以获得最大的代码覆盖率 例如我有这个方法 protected static void checkifValidElements int arg1 int arg2 metho
  • 在 java 中运行外部应用程序但不要等待它完成

    我正在用java编写一个应用程序 允许我运行其他应用程序 为此 我使用了 Process 类对象 但当我这样做时 应用程序会等待进程结束 然后再退出 有没有办法在 Java 中运行外部应用程序 但不等待它完成 public static v
  • C 与 C++ 中的 JNI 调用不同?

    所以我有以下使用 Java 本机接口的 C 代码 但是我想将其转换为 C 但不知道如何转换 include
  • 使用单独的线程在java中读取和写入文件

    我创建了两个线程并修改了 run 函数 以便一个线程读取一行 另一个线程将同一行写入新文件 这种情况会发生直到整个文件被复制为止 我遇到的问题是 即使我使用变量来控制线程一一执行 但线程的执行仍然不均匀 即一个线程执行多次 然后控制权转移
  • BadPaddingException:无效的密文

    我需要一些帮助 因为这是我第一次编写加密代码 加密代码似乎工作正常 但解密会引发错误 我得到的错误是 de flexiprovider api exceptions BadPaddingException 无效的密文 in the 解密函数
  • 如何以编程方式创建 CardView

    我正在开发一个 Android 应用程序Java Android Studio 我想在活动中创建CardView以编程方式 我想将以下属性设置为CardView layout width wrap content layout row 0
  • 如何在 O(n) 时间内根据 Map 中的整数值相对于其他值随机选择一个键?

    如果我们有一个Map
  • Android UnityPlayerActivity 操作栏

    我正在构建一个 Android 应用程序 其中包含 Unity 3d 交互体验 我已将 Unity 项目导入 Android Studio 但启动时该 Activity 是全屏的 并且不显示 Android 操作栏 我怎样才能做到这一点 整
  • Java/MongoDB 按日期查询

    我将一个值作为 java util Date 存储在我的集合中 但是当我查询以获取两个特定日期之间的值时 我最终得到的值超出了范围 这是我的代码 插入 BasicDBObject object new BasicDBObject objec

随机推荐

  • 第七章、并发编程实战项目

    一 并发任务执行框架 架构师是什么 在一个软件项目开发过程中 将客户的需求转换为规范的开发计划及文本 并制定这个项目的总体架构 指导整个开发团队完成这个计划的那个人 就是 架构师 一般是一个项目里的最资深的专业技术人员 可以说架构师首先一定
  • 【SDOI2016】数字配对【建立二分图+费用流求方案数】

    题目链接 首先 我们可以看一下这个推导过程 如果 那么 对于 就一定不是质数 一定是它的一个因子 于是可以看出 这一定是一幅二分图 于是 可以根据二分图的性质来确定了每个点的属于S边还是T边了 include
  • 《深入理解mybatis原理》 MyBatis事务管理机制

    版权声明 本文为博主原创文章 未经博主允许不得转载 https blog csdn net u010349169 article details 37992171 MyBatis作为Java语言的数据库框架 对数据库的事务管理是其非常重要的
  • 在手机端点击input框不弹出输入法的方法

    1 使用CSS样式 input pointer events none 2 使用事件阻止 input onmousedown function e e preventDefault 这样不仅会阻止键盘 同时 input 会失去光标跟随 如果
  • 通俗易懂的LSTM

    目录 一 LSTM的基础知识 1 长依赖的问题 2 LSTM的核心 3 LSTM的门结构 4 LSTM门结构的作用 5 LSTM的变体 GRU 二 LSTM的补充知识 1 LSTM缓解梯度消失的原因 一 LSTM的基础知识 1 长依赖的问题
  • Python OpenCV 解决人脸识别报错cascade.detectMultiScale error

    Authored by Monana Contact me via serena9636 163 com 环境 Python2 7 OpenCV3 1 0 Win 64bit 我想在OpenCV中实现一段如下的很简单的人脸识别代码 这也是在
  • vsCode返回上一步

    vsCode返回上一步 windows Alt 上下左右的左箭头 Linux Ctrl Alt 减号
  • 图像信噪比的理解

    图像的信噪比和图像的清晰度一样 都是衡量图像质量高低的重要指标 图像的信噪比是指视频信号的大小与噪波信号大小的比值 其公式为 S N 信噪比 20 log 信号 噪声 dB 信噪比大 图像画面就干净 看不到什么噪波干扰 表现为 颗粒 和 雪
  • 使用VMware完成KVM虚拟化实验并运行Centos

    本次实验在VMware中的Ubuntu18内安装KVM并运行centos 首先 在VMware下开启虚拟化 更新软件索引 apt get update 安装依赖 apt get install qemu kvm qemu virt mana
  • js验证姓名,包括少数民族名字中的·,后你哦·就两节课了

    姓名验证 u4E00 u9FA5 uf900 ufa2d s 2 20 亲测
  • Outlook VBA自动处理邮件

    需求描述 公司里面每天都会有很多邮件 三分之一都是不需要看的 Outlook的过滤功能不错 都可以处理掉 还有些邮件 根据正文或者附件做一下处理自动转发出去就行了 于是上网搜集了一些资料 写个了小程序 共享一下 以后可以参考 也希望对大家有
  • Linux系列一 VMware 中 Fedora系统的安装与网络配置

    之前一篇文章 简单地总结了自己的Linux假期培训课程 因为自己也打算开始学习Linux 所以就在这里写点东西 记录自己的学习历程 如果也能给大家带去一点帮助的话 甚是欣慰 能力时间有限 难免有疏漏的地方 还希望大家多多批评指正 本篇文章的
  • C++——set 和 multiset

    文章目录 结构 构造 非更易型操作 查找操作 赋值操作 迭代器相关操作 插入和移除操作 自定义排序准则 Set 和 multiset 会根据特定的排序准则 自动将元素排序 两者不同之处在于 multiset 允许元素重复而 set 不允许
  • [bzoj1359][Baltic2009]Candy

    给定N个数对 T i S i 表示时刻 S i 时在位置 T i 处出现一粒糖果 有一些机器人可供使用 每个机器人可花费一单位时间向相邻位置移动 要求用最少的机器人接到全部糖果 时刻0时机器人位置可自行安排 1 leq N leq10000
  • centos断电重启卡在登录前界面的问题解决

    出现这个情况的原因猜测是断电 启动后就卡在登录前界面 只有网络是通的 其他服务貌似都没正常启动 ssh远程终端也连不上 ctrl alt 1 切换到详细信息模式下看到这样的错误 就是文件系统xfs有损坏 查资料都说是需要通过xfs repa
  • c语言编程3*3矩阵的转置

    include
  • 【FreeRTOS】任务通知的使用

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • Java比较两个对象是否相同并获取值不同的属性

    最近项目中要加操作日志 同时要把用户修改了那些字段记录下来 在更新的时候就需要比较之前的数据和现在的数据有哪些不同 这么多类一个一个的比较就太麻烦了 所以打算写一个工具类 主要思想还是通过反射获取类的属性的getter方法 调用getter
  • 【Mo 人工智能技术博客】基于耦合网络的推荐系统

    基于耦合网络的推荐系统 作者 陈东瑞 1 复杂网络基础知识 当我们拿起手机给家人 朋友或者同事拨打电话时 就不知不觉中参与到了社交网络形成的过程中 当我们登上高铁或者飞机时 就可以享受交通网络给我们带来的方便 即使当我们躺在床上什么也不干时
  • 【Java小实验】【Java并发】使用线程池按行并发取二维数组最大值

    使用线程池按行并发取二维数组最大值 生成二维数组 使用Callable实现线程 使用Runnable获取线程 快手后端二面问题 由于网上直接搜竟然没有搜出来 自己写了一下 生成二维数组 生成二维数组的公共类 class RandomArra