Java并发编程初探

package test;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void getJavaFile(String currentpath,List<File> files){
        File dir = new File(currentpath);
        if(dir.exists()){
            File temp[] = dir.listFiles();
            if(temp != null)
            {
                for (File b: temp) {
                    if (b.isFile() && b.toString().endsWith(".java")) {
                        files.add(b);
                    }
                    else if(b.isDirectory()){
                        getJavaFile(b.toString(), files);
                    }
                }
            }
        }
    }
    public final static float percent = (float) 0.9;
    public final static int poolsize = (int) (Runtime.getRuntime().availableProcessors()/(1-percent));
    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        //初始化文件集合
        String path = "G:"+File.separator+"src";
        List<File> fs = new ArrayList<>();
        getJavaFile(path, fs);

        //顺序执行
        long start = System.currentTimeMillis();
        int total = 0;
        for(File s : fs){
            int i = getCount(s);
            //System.out.println(s.getName()+"长度为:"+i);
            total+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println("顺序执行的时间:"+(end-start)+"得出来的结果:"+total);

        final ExecutorService executorpool = Executors.newFixedThreadPool(poolsize);
        final List<Callable<Integer>> partitions = new ArrayList<>();
        for(final File f1 : fs){
            partitions.add(new Callable<Integer>() {

                @Override
                public Integer call() throws Exception {
                    // TODO Auto-generated method stub
                    Integer i = getCount(f1);
                    //System.out.println(f1.getName()+"长度为:"+i);
                    return i;
                }
            });
        }
        long startbingfa = System.currentTimeMillis();
        final List<Future<Integer>> nums = executorpool.invokeAll(partitions,5,TimeUnit.MINUTES);
        int totalbingfa = 0;
        for(final Future<Integer>i : nums){
                totalbingfa = totalbingfa+i.get();
        }
        executorpool.shutdown();
        long endbingfa = System.currentTimeMillis();
        System.out.println("并发的时间:"+(endbingfa-startbingfa)+"得出来的结果:"+totalbingfa);

    }

    public static int getCount(File f) throws IOException{
        int count = 0;
        Reader br = new FileReader(f);
        //String line = "";
        int c;
        while ((c = br.read()) != -1) {
            if(‘a‘ == (char)c){
                count++;
            }
        }
        return count;
    }
}

上面可以看到,我设置了大量的文件,然后使用并发和顺序执行,执行结果如下:

顺序执行的时间:140得出来的结果:14002
并发的时间:86得出来的结果:14002

可以看到,其实改进并不特别明显,究其原因就是,代码中的任务的IO密集型特征并不明显,但是就这个而言,时间仍然是有所改进的,采用的是线程池方式,首先定义一个任务集合partitions,

final List<Callable<Integer>> partitions = new ArrayList<>();

其中Integer表示的是任务的返回类型

然后给任务集定义任务,比如上面的就是一个读取文件并且返回一个Integer类型的数据.

然后定义任务服务

final ExecutorService executorpool =Executors.newFixedThreadPool(poolsize);

这里设置的是线程池的大小,也就是能够同时运行的任务数.

然后开始执行

final List<Future<Integer>> nums = executorpool.invokeAll(partitions,5,TimeUnit.MINUTES);

这里返回的是任务集合的全体的返回结果,然后我们遍历nums,用get方法去得到单个结果.

最后要关闭线程池

executorpool.shutdown();

线程池的大小并不是设置的越大越好,根据具体的环境而来,

时间: 2024-10-11 17:35:47

Java并发编程初探的相关文章

【java并发编程艺术学习】(三)第二章 java并发机制的底层实现原理 学习记录(一) volatile

章节介绍 这一章节主要学习java并发机制的底层实现原理.主要学习volatile.synchronized和原子操作的实现原理.Java中的大部分容器和框架都依赖于此. Java代码 ==经过编译==>Java字节码 ==通过类加载器==>JVM(jvm执行字节码)==转化为汇编指令==>CPU上执行. Java中使用的并发机制依赖于JVM的实现和CPU的指令. volatile初探 volatile是是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性.可见性

Java并发编程:Concurrent锁机制解析

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

Java并发编程:Callable、Future和FutureTask(转)

Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. 今天我们就来讨论一下Callabl

Java并发编程 Volatile关键字解析

volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的. 2)禁止进行指令重排序. 根据volatile的语义,我们可以看到,volatile主要针对的是并发三要素(原子性,可见性和有序性)中的后两者有实际优化作用. 可见性: 线程本身并不直接与主内存进行数据的交互,而是通过线程的工作内存来完成相应的操作.

Java并发编程

synchronized是Java中的关键字,在并发编程中被称为内置锁或者监视器锁.当用它来修饰一个方法或者一个代码块的时候能够保证同一时刻最多只有一个线程执行该段代码. Java的内置锁相当于一种互斥锁,最多只有一个线程能够持有这种锁,故而由这个锁保护的同步代码块会以原子方式执行,多个线程在执行该代码时就不会相互干扰. 但由于被锁保护的同步块代码是以串行形式来访问的,即多个线程以独占的方式访问对象,而这也导致如果被锁保护的同步代码块的作用范围过大,会导致并发不良. 这里有必要简单讲一下内置锁的

6、Java并发编程:volatile关键字解析

Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatil

7、Java并发编程:深入剖析ThreadLocal

Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两个应用场景. 以下是本文目录大纲: 一.对ThreadLocal的理解 二.深入解析ThreadLocal类 三.ThreadLocal的应用场景 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者

java并发编程实战学习(3)--基础构建模块

转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put方法将阻塞直到空间可用:如果队列为空,那么take方法将阻塞直到有元素可用.队列可以是有界的也可以是无界的. 如果生产者生成工作的速率比消费者处理工作的速率款,那么工作项会在队列中累计起来,最终好紧内存.同样,put方法的阻塞特性也极大地简化了生产者的编码.如果使用有界队列,当队列充满时,生产者将阻

Java 并发编程之任务取消(九)

Jvm关闭 jvm可正常关闭也可强行关闭,正常关闭有多种触发方式: 当最后一个正常(非守护,下面会讲到什么是守护线程)线程结束时 当调用system.exit时,或者通过其他特定于平台的方法关闭时(例如发送了SIGINT信号或键入Ctrl-c) 通过其他特定平台的方法关闭jvm,调用Runtime.halt或者在操作系统当中杀死JVM进程(例如发送sigkill)来强行关闭jvm. 关闭钩子 在正常关闭中,jvm首先调用所有已注册的关闭钩子,关闭钩子是指通过 Runtime.addShutdow