java 多线程学习笔记(一) -- 计算密集型任务

最近在看《Java虚拟机并发编程》,在此记录一些重要的东东。

线程数的确定:
1. 获取系统可用的处理器核心数:int numOfCores = Runtime.getRuntime().availableProcessors()
2. 如果任务是计算密集型的,则线程数 = numOfCores
        如果任务是IO密集型的,则线程数 = numOfCores / (1 - 阻塞系数), 其中阻塞系数在0~1之间。
注:如果任务被阻塞的时间大于执行时间, 则这些任务是IO密集型的,我们就需要创建比处理器核心数大几倍数量的线程

在解决问题的过程中使处理器一直保持忙碌状态比将负载均摊到每个子任务要实惠得多。
任务完成并不代表线程消亡。

计算密集型任务:如求1到10000000内所有素数的个数

1. AbstractPrimeFinder

public abstract class AbstractPrimeFinder {

    public boolean isPrime(final int number){
        if(number <= 1) return false;

        for(int i = 2; i <=Math.sqrt(number); i++){
            if (number % i == 0)
                return false;
        }
        return true;
    }

    public int countPrimesInRange(final int lower, final int upper){
        int total = 0;
        for( int i = lower; i <= upper; i++){
            if(isPrime(i))
                total++;
        }
        return total;
    }

    public void timeAndComputer(final int number){
        long start = System.nanoTime();
        int numberOfPrimes = countPrimes(number);
        long end = System.nanoTime();

        System.out.printf("Number of primes under %d is %d\n", number, numberOfPrimes);
        System.out.println("Spend time(seconds) is " + (end-start)/1.0e9);
    }

    public abstract int countPrimes(final int number);
}

2. ConcurrentPrimeFinder

/**
 * 对于计算密集型的任务,增加线程数并没有什么意义,线程数应该等于CPU内核数。如果较难把任务均摊到CPU,则
 * 可以把任务切分成较多块,以确保CPU完成某块任务后,可以继续处理其它块。防止某个CPU完成任务后处于空闲状态。
 * @author shj
 *
 */
public class ConcurrentPrimeFinder extends AbstractPrimeFinder{
    private final int poolSize;
    private final int numberOfParts;

    public ConcurrentPrimeFinder(int poolSize, int numberOfParts){
        this.poolSize = poolSize;
        this.numberOfParts = numberOfParts;
    }

    @Override
    public int countPrimes(final int number) {
        int count = 0 ;
        try{
            List<Callable<Integer>> partitions = new ArrayList<>();
            int chunksPerPartition = number / numberOfParts;
            for(int i = 0; i < numberOfParts; i++){
                final int lower = (i * chunksPerPartition) + 1;
                final int upper = (i == numberOfParts - 1) ? number : lower + chunksPerPartition - 1;
                partitions.add(new Callable<Integer>(){
                    public Integer call(){
                        return countPrimesInRange(lower, upper);
                    }
                });
            }

            ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);
            List<Future<Integer>> results = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
            executorPool.shutdown();

            for(Future<Integer> result : results){
                count += result.get();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return count;
    }

    public static void main(String[] args){
        int cores = Runtime.getRuntime().availableProcessors();
        int numberOfParts = 20; //划分成子区间的数量, 修改此值查看运行时间的变化
        new ConcurrentPrimeFinder(cores,numberOfParts).timeAndComputer(10_000_000);
    }
}
时间: 2024-10-12 17:28:01

java 多线程学习笔记(一) -- 计算密集型任务的相关文章

Java多线程学习笔记--生产消费者模式

实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前水平只能膜拜,本次只能算学习笔记,为了巩固自己对Java多线程常规知识点的理解,路过大神还望能指导指导.下面一段代码是最常规的生产者消费者的例子: package com.zhanglei.demo; import java.util.ArrayList; import java.util.List

Java 多线程学习笔记:生产者消费者问题

前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后,自行实现阻塞队列. (一)准备 在多线程中,生产者-消费者问题是一个经典的多线程同步问题.简单来说就是有两种线程(在这里也可以做进程理解)——生产者和消费者,他们共享一个固定大小的缓存区(如一个队列).生产者负责产生放入新数据,消费者负责取出缓存区的数据.具体介绍请参考 Producer-consumer

Java多线程学习笔记(一)

一 概述 一个进程只有一个至少会运行一个线程,Java中同样存在这样,在调用main方法的时候,线程又JVM所创建. 1 package link.summer7c.test; 2 3 public class Test{ 4 public static void main(String[] args){ 5 System.out.println(Thread.currentThread().getName()); 6 } 7 } 运行结果:main 叫做main的线程正在执行main()方法中

Java多线程学习笔记1

1.线程的基本概念 一个关于计算机的简化的视图是: 它有一个执行计算的处理机. 包含处理机所执行的程 序的 ROM(只读存储器). 包含程序所要操作的数据的 RAM(只读存储器).线程,被认为是带有自己的程 序代码和数据的拟处理机的封装.线程的三个部分处理机,代码,数据. 代码可以或不可以由多个线程共享, 这和数据是独立的. 两个线程如果执行同一个类的 实例代码,则它们可以共享相同的代码. 类似地,数据可以或不可以由多个线程共享, 这和代码是独立的. 两个线程如果共享对 一个公共对象的存取,则它

Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解

   我们知道在多线程编程中,我们很大的一部分内容是为了解决线程间的资源同步问题和线程间共同协作解决问题.线程间的同步,通俗我们理解为僧多粥少,在粥有限情况下,我们怎么去防止大家有秩序的喝到粥,不至于哄抢都没得喝.线程讲协作,我们可以理解为我们在医院看病的时候,我们要先挂号,才能看病.现在医院有很多病人排队,怎么协调病人都有秩序的先挂号,后看病.本篇文章的重点不在此,也不是在此一下子能分析完,我们先从Java JVM的角度来理解多线程的一些方面. 我们知道多线程间的数据同步,我们是通过加锁的操作

java多线程学习笔记——简单

进程:程序(任务)的执行过程——动态性. 持有资源(共享内存,共享文件)和线程. 线程:线程是系统中最小的执行单元,统一进程中有多个线程,线程共享进程的资源. 线程交互:互斥与同步. 注意:多线程是异步的,所以千万不要把Eclipse里代码的顺序当成线程执行的顺序,线程被调用的时机是随机的. java对线程的支持: class Thread    interface Runnable    共同的run方法 线程的创建和启动: 线程常用方法: 如何停止线程: java中有三种方法可以终止正在运行

Java多线程学习笔记——信号量的使用

Java中在控制多线程访问资源的时候使用了信号量可以控制多个线程同时访问一个资源. 有两个构造方法: public Semaphore(int permits) public Semaphore(int permits,boolean fair) 第二个参数和重入锁一样,是指定是否公平.(公平是要牺牲性能的) 1 public class SignalNum implements Runnable { 2 Semaphore semaphore=new Semaphore(2); 3 4 5 @

java多线程学习笔记

一.线程的创建 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有.此时观察Thread类,有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多线程.(start()可以协调系统的资源)

JAVA多线程学习笔记&lt;3&gt;线程传入参数与终止线程方法

public class TimeThread extends Thread { private long start; public volatile boolean exit = false; public TimeThread(long start) { this.start = start; } public void run() { while(!exit) { long end = System.currentTimeMillis(); long useTime = end - st