巧用CountDownLatch实现多线程并行工作

这篇具有很好参考价值的文章主要介绍了巧用CountDownLatch实现多线程并行工作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【前言】
      CountDownLatch是JDK提供的一个同步工具,它可以让一个或多个线程挂起等待,一直等到其他线程执行完成才会继续执行。常用方法有countDown方法和await方法,CountDownLatch在初始化时,需要指定一个整数n作为计数器。当调用countDown方法时,计数器会被减1;当调用await方法时,如果计数器大于0时,当前线程会被阻塞,一直到计数器被countDown方法减到0时,当前线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用await方法都会直接返回。

一、使用场景:扫描手机内的安装包

      由于手机文件夹目录众多,单线程遍历全部文件夹找出所有的安装包会比较费时,但是假如开启多个线程并行去搜索不同的文件夹,然后再将结果汇总起来返回,那么效率就会明显有所提高。然而开启多个线程去搜索是很容易实现,但是由于每个线程耗时不同,有些线程搜索完毕了,但是有些线程可能还在搜索,怎么确保所有的线程都搜索完毕再把结果汇总起来返回呢?这时候借助CountDownLatch这个类就能轻易地实现

二、场景案例实现

1、开启多线程遍历文件夹,这里使用线程池去实现,以便达到线程复用的目的

  /**
     * 扫描手机外存所有目录查找apk文件,需要读取外部权限
     */
    public void scanAllApks(Context context) {
        //避免多线程同时访问
        synchronized (INSTANCE){
            // 公共储存下的所有文件
            File[] files = Environment.getExternalStorageDirectory().listFiles();
            // 私有存储目录下的文件
            File filesDir = context.getExternalFilesDir(null);

            //多线程并发执行扫描
            if (executorService == null) {
                executorService = Executors.newFixedThreadPool(10);
            }

            //遍历
            List<Runnable> runnableList = new ArrayList<>();
            if (files != null) {
                List<File> fileList = new ArrayList<>();
                fileList.add(filesDir);
                fileList.addAll(Arrays.asList(files));
                for (File file : fileList) {
                    if (file.isDirectory()) {
                        //当前是目录的话,构造一个Runnale对象,稍后放到线程池去执行
                        runnableList.add(new SearchApkRunnable(file));
                    } else {
                        //当前是文件的话,尝试直接去解析
                        tryToParseApk(context, file);
                    }
                }
            }

            //初始化一个计数为文件夹总数的计数器
            countDownLatch = new CountDownLatch(runnableList.size());
            //使用线程池去执行遍历任务
            for(Runnable runnable: runnableList){
                executorService.execute(runnable);
            }

            try {
                //当前线程会堵塞在这里,直到所有线程执行完毕才会继续往下执行
                countDownLatch.await();
                Logger.i("扫描完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
                Logger.e("扫描被打断");
            }

        }
    }

2、每个线程所做的事情就是递归去查找当前目录下的所有安装包,线程执行完毕会调用CountDownLatchcountDown()方法将计数器减一

    public class SearchApkRunnable implements Runnable{
        private File mFile;
        private Context mCxt;
        public SearchApkRunnable(Contex context, File file){
            this.mFile = file;
            this.mCxt = context;
        }
        @Override
        public void run() {
            try {
                scanDirToFindApk(mCxt, this.mFile);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //计数减一
               countDownLatch.countDown();
            }

        }
    }


    /**
     * 扫描目录,查找apk文件
     *
     * @param dir
     */
    private void scanDirToFindApk(Context context, File dir) {
        if (Thread.currentThread().isInterrupted()) {
            Logger.d("扫描终止:"+ Thread.currentThread().getName());
            return;
        }

        File[] files = dir.listFiles();
        if (files != null && files.length > 0) {
            for (File f : files) {
                //递归查找
                if (f.isDirectory()) {
                    //扫描目录
                    scanDirToFindApk(context,f);
                } else {
                    //是文件的话,尝试解析apk信息
                    tryToParseApk(context,f);
                }
            }
        }
    }
   

3、查找发现是文件时候,若是apk后缀的文件,尝试解析出apk的信息文章来源地址https://www.toymoban.com/news/detail-637758.html

 /**
     * 尝试解析APk信息
     *
     * @param file
     * @return
     */
    private ApkInfo tryToParseApk(Context context, File file) {
        if (file == null) {
            return null;
        }

        String absolutePath = file.getAbsolutePath();
        //判断是apk
        if (absolutePath.endsWith(".apk")) {
            //过滤掉小于0.1M的apk
            if (file.length() >= 1024*100) {
                PackageInfo packageInfo;
                ApkInfo apkInfo;
                try {
                    PackageManager packageManager = context.getPackageManager();
                    packageInfo = packageManager.getPackageArchiveInfo(absolutePath, PackageManager.GET_ACTIVITIES);
                    if(packageInfo == null){
                        return null;
                    }
                    //一定要设置sourceDir 与 publicSourceDir,否则获取不到label与icon
                    apkInfo = createApkInfo(file, packageInfo, packageManager);
                    //加入安装包集合ArrayList中
                    APK_INFOS.add(apkInfo);
                    return apkInfo;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }

        }

        return null;
    }
    @NonNull
    private ApkInfo createApkInfo(File file,  PackageInfo packageInfo, PackageManager packageManager) {
        ApkInfo apkInfo;
        ApplicationInfo applicationInfo = packageInfo.applicationInfo;
        if(TextUtils.isEmpty(applicationInfo.sourceDir)){
            applicationInfo.sourceDir = file.getAbsolutePath();
            applicationInfo.publicSourceDir = file.getAbsolutePath();
        }
        String appName = applicationInfo.loadLabel(packageManager).toString();
        Drawable icon = applicationInfo.loadIcon(packageManager);
        String packageName = packageInfo.packageName;
        String versionName = packageInfo.versionName;
        int versionCode = packageInfo.versionCode;
        long apkSize = file.length();
        apkInfo = new ApkInfo(appName, packageName, versionCode, versionName, icon, apkSize, file.getAbsolutePath(), file.getName());
        return apkInfo;
    }

到了这里,关于巧用CountDownLatch实现多线程并行工作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • CountDownLatch介绍和使用【Java多线程必备】

    点击   Mr.绵羊的知识星球  解锁更多优质文章。 目录 一、介绍 二、特性 三、实现原理 四、适用场景 五、注意事项 六、实际应用     CountDownLatch 是 Java 中的一个并发工具类,用于协调多个线程之间的同步。其作用是让某一个线程等待多个线程的操作完成之后再执行。它可

    2024年02月05日
    浏览(53)
  • CountDownLatch使用错误+未最终断开连接导致线程池资源耗尽

            我设置了CountDownLatch对线程的协作做出了一些限制,但是我发现运行一段时间以后便发现定时任务不运行了。 具体代码: 报错以后定时任务不运行了   打印线程日志发现定时任务的线程在第86行代码停着不动了。 正常的线程日志应该是这样的。 查看第86行代码,

    2024年04月24日
    浏览(38)
  • 2. postgresql并行扫描(1)——pg强制走并行扫描建表及参数配置

    转载自:https://developer.aliyun.com/article/700370 max_parallel_workers_per_gather 参数控制执行节点的最大并行进程数,通过以上并行计划可知,开启并行后,会启动两个 worker 进程(即 Workers Launched: 2)并行执行 https://developer.aliyun.com/article/684431 并行扫描的理念很朴素,即启动多个 worker

    2024年02月09日
    浏览(35)
  • 原子类-入门介绍和分类说明、基本类型原子类、Join和CountDownLatch都可以让一个线程等待子线程完成

    Atomic翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学 反应中是不可分割的。在我们这里Atomic是指一个操作是不可中断的。即使是在多个线程一起执 行的时候,一个操作一旦开始,就不会被其他线程干扰。 基本类型原子类 AtomicInteger :

    2024年01月20日
    浏览(38)
  • 【Java基础教程】(四十二)多线程篇 · 上:多进程与多线程、并发与并行的关系,多线程的实现方式、线程流转状态、常用操作方法解析~

    理解进程与线程的区别; 掌握Java 中多线程的两种实现方式及区别; 掌握线程的基本操作方法; 进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程 。多进程操作系统能同时运行多

    2024年02月16日
    浏览(47)
  • 20230830工作心得:巧用标记位和For循环遍历

    您可以使用一个 `MapString, Listxxx` 类型的数据结构来根据手机号分组并保存多条线索。然后,可以按照以下方式进行操作: 1. 设置一个标志位,比如一个布尔变量,用于记录是否已经成功推送了第一条线索。 2. 遍历 `Map` 的键集合(即手机号集合)。 3. 对于每个键(手机号)

    2024年02月10日
    浏览(42)
  • 巧用 ChatGPT,让开发者的学习和工作更轻松

    随着人工智能技术的快速发展和广泛应用,ChatGPT 作为一种新兴的自然语言处理模型,近期备受瞩目,引发了广泛讨论。 ChatGPT 具有多种应用场景,既可以用作聊天机器人,实现智能问答和自然语言交互,也可以作为文本生成工具,帮助人们撰写文章、新闻和小说等。 作为一

    2023年04月08日
    浏览(34)
  • C/C++ 线程池工作原理 & 代码实现

    如果多次使用线程,那么就需要多次的创建并撤销线程。但是创建/撤销的过程会消耗资源。 线程池是一种数据结构,其中维护着多个线程 ,这避免了在处理短时间任务时,创建与销毁线程的代价。即在程序开始运行前预先创建一定数量的线程放入空闲队列中,这些线程都是

    2024年02月12日
    浏览(29)
  • Android studio 实现生成二维码和扫描二维码

    效果图 build.gradle(:app)添加依赖 Manifests.xml activity_main.xml MainActivity ScanActivity

    2024年02月10日
    浏览(47)
  • Android实现生成二维码以及扫描二维码的功能(超级简单!)

    文章目录 ​​​​​​ 前言 二、实现生成二维码的功能 三、实现扫面二维码的功能 总结 提示:这里可以添加本文要记录的大概内容: 我是通过一个第三方库来实现二维码的生成,以及扫描二维码的功能,开源库如下: 一、布局文件如下 布局比较简单,就只有简单的一些

    2024年02月12日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包