Java多线程-素数计算

单线程即串行方式计算素数

package prime.witersen;

public class pc_serial {

    private static final int NUM_END = 200000;

    public static void main(String[] args) {
        int counter = 0;
        int i;

        long startTime = System.currentTimeMillis();
        for (i = 0; i < NUM_END; i++) {
            if (isPrime(i))
                counter++;
        }
        long endTime = System.currentTimeMillis();
        long timeDiff = endTime - startTime;
        System.out.println("执行时间:  " + timeDiff + " ms");
        System.out.println("素数个数: " + counter);
    }

    private static boolean isPrime(int x) {
        int i;
        if (x <= 1)
            return false;
        for (i = 2; i < x; i++) {
            if ((x % i == 0) && (i != x))
                return false;
        }
        return true;
    }

}

静态负载平衡方式1,即在进行编程时为每个线程分配工作,指定每个线程的计算范围

按照均分的方式分配每个线程的计算量

package prime.witersen;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class pc_static_1 {

    // 素数范围 0-NUM_END
    private static final int NUM_END = 200000;

    // 对素数计数
    private static AtomicInteger COUNT = new AtomicInteger(0);

    // 线程数
    private static int THREAD_NUM = 10;

    public static void main(String[] args) throws InterruptedException {

        // 以线程数作为计数依据 达到等待子线程结束目的
        CountDownLatch latch = new CountDownLatch(THREAD_NUM);

        // 按照均分的方式分配每个线程的计算量
        int base = NUM_END / THREAD_NUM;

        // 创建指定数量的线程
        TestThread[] threads = new TestThread[THREAD_NUM];
        for (int i = 0; i < THREAD_NUM; i++) {
            threads[i] = new TestThread(base * i + 1, base * i + base, latch);
            threads[i].setName((i+1)+"");
        }

        // 开始计时
        long startTime = System.currentTimeMillis();

        // 启动线程
        for (int i = 0; i < THREAD_NUM; i++) {
            threads[i].start();
        }

        // 等待子线程结束
        latch.await();

        // 结束计时
        long endTime = System.currentTimeMillis();

        System.out.println("总耗时:" + (endTime - startTime) + " ms");

        System.out.println("素数个数:" + COUNT.get());
    }

    // 线程类
    static class TestThread extends Thread {
        int startPos, endPos;
        CountDownLatch latch;

        public TestThread(int start, int end, CountDownLatch latch) {
            this.startPos = start;
            this.endPos = end;
            this.latch = latch;
        }

        public void run() {
            
            // 每个线程内的开始计时
            long startTime = System.currentTimeMillis();

            getPrime(startPos, endPos);

            // 每个线程内的结束计时
            long endTime = System.currentTimeMillis();

            System.out.println("单线程" + Thread.currentThread().getName() + "耗时:" + (endTime - startTime) + " ms");
            
            latch.countDown();
        }
    }

    // 判断是否为素数
    static boolean isPrime(int x) {
        int i;
        if (x <= 1)
            return false;
        for (i = 2; i < x; i++) {
            if ((x % i == 0) && (i != x))
                return false;
        }
        return true;
    }

    // 判断一个给定范围内的素数个数
    static void getPrime(int start, int end) {
        for (int i = start; i <= end; i++) {
            if (isPrime(i)) {
                COUNT.getAndIncrement();
            }
        }
    }

}

静态负载平衡方式2,即在进行编程时为每个线程分配工作,指定每个线程的计算范围

不按照均分的方式为每个线程分配工作量,而是手动调整,因为素数判断到后面数字越大处理耗费的时间越长

package prime.witersen;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

public class pc_static_2 {

    // 素数范围 0 - ?
    private static final int NUM_END = 200000;

    // 最大并发数
    private static final int CPU_CORE_NUM = 5;

    // 对素数计数
    private static AtomicInteger integer = new AtomicInteger();

    public static void main(String[] args) {

        // 创建一个定长的线程池 可控制线程的最大并发数 超出的线程会在队列中等待
        ExecutorService service = Executors.newFixedThreadPool(CPU_CORE_NUM);

        // 素数判断到后面数字越大处理耗费的时间越长 速度越慢 此处虽然为均分 但是如果要加快计算速度 可以将大范围的数据加到前面的线程
        // 如1-80000 80001-100000
        // 其中的 1 2 3 4 5为序号 可使打印结果更直观
        MyTask t1 = new MyTask(1, 40000, 1);
        MyTask t2 = new MyTask(40001, 80000, 2);
        MyTask t3 = new MyTask(80001, 120000, 3);
        MyTask t4 = new MyTask(120001, 160000, 4);
        MyTask t5 = new MyTask(160001, 200000, 5);

        Future<Integer> s1 = service.submit(t1);
        Future<Integer> s2 = service.submit(t2);
        Future<Integer> s3 = service.submit(t3);
        Future<Integer> s4 = service.submit(t4);
        Future<Integer> s5 = service.submit(t5);

        // 开始计时
        long startTime = System.currentTimeMillis();
        try {
            s1.get();
            s2.get();
            s3.get();
            s4.get();
            s5.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        // 结束计时
        long endTime = System.currentTimeMillis();

        System.out.println("总耗时:" + (endTime - startTime) + " ms");

        System.out.println("素数个数:" + integer.get());

        service.shutdown();
    }

    // 获取线程有继承Thread类、实现runnable接口、实现callable接口三种方法 这里使用第三种
    static class MyTask implements Callable<Integer> {

        int startPos, endPos, sign;

        MyTask(int start, int end, int sign) {
            this.startPos = start;
            this.endPos = end;
            this.sign = sign;
        }

        @Override
        public Integer call() throws Exception {

            // 每个线程内的开始计时
            long startTime = System.currentTimeMillis();

            getPrime(startPos, endPos);

            // 每个线程内的结束计时
            long endTime = System.currentTimeMillis();

            System.out.println("单线程" + sign + "耗时:" + (endTime - startTime) + " ms");

            return integer.get();
        }
    }

    // 判断是否为素数
    static boolean isPrime(int x) {
        int i;
        if (x <= 1)
            return false;
        for (i = 2; i < x; i++) {
            if ((x % i == 0) && (i != x))
                return false;
        }
        return true;
    }

    // 判断一个给定范围内的素数个数
    static void getPrime(int start, int end) {
        for (int i = start; i <= end; i++) {
            if (isPrime(i)) {
                integer.getAndIncrement();
            }
        }
    }

}

动态负载平衡方式

多线程中的每个线程不指定分配量,每个线程拿到哪个任务就计算哪个任务,这种方式效率最高

package prime.witersen;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class pc_dynamic {

    // 素数范围 0 - NUM_END
    private static AtomicInteger NUM_END = new AtomicInteger(200000);

    // 最大并发数
    private static final int CPU_CORE_NUM = 32;
    
    // 线程数
    private static int THREAD_NUM = 10;

    // 对素数计数
    private static AtomicInteger COUNT = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException {

        // 创建一个定长的线程池 控制线程的最大并发数 超出的线程会在队列中等待
        ExecutorService service = Executors.newFixedThreadPool(CPU_CORE_NUM);

        // 用于批量添加线程
        List<Callable<Integer>> callableList = new ArrayList<Callable<Integer>>();

        // 创建线程
        for (int i = 0; i < THREAD_NUM; i++) {
            
            final int sign = i;
            
            // 直接使用匿名内部类
            callableList.add(new Callable<Integer>() {

                @Override
                public Integer call() throws Exception {

                    // 每个线程内的开始计时
                    long startTime = System.currentTimeMillis();

                    while (NUM_END.get() != 0) {

                        int temp = NUM_END.getAndDecrement();

                        // 打印空内容不能去掉
                        System.out.print("");

                        if (isPrime(temp)) {
                            COUNT.getAndIncrement();
                        }
                    }

                    // 每个线程内的结束计时
                    long endTime = System.currentTimeMillis();

                    System.out.println("单线程" + sign + "耗时:" + (endTime - startTime) + " ms");

                    return COUNT.get();
                }
            });
        }

        // 开始计时
        long startTime = System.currentTimeMillis();

        service.invokeAll(callableList, 10000, TimeUnit.SECONDS);

        // 结束计时
        long endTime = System.currentTimeMillis();

        // 及时关闭
        service.shutdown();

        System.out.println("总耗时:" + (endTime - startTime) + " ms");

        System.out.println("素数个数:" + COUNT.get());
    }

    // 判断是否为素数
    static boolean isPrime(int x) {
        int i;
        if (x <= 1)
            return false;
        for (i = 2; i < x; i++) {
            if ((x % i == 0) && (i != x))
                return false;
        }
        return true;
    }

}

原创文章,作者:witersen,如若转载,请注明出处:https://www.witersen.com

(2)
witersen的头像witersen
上一篇 2021年4月21日 上午12:40
下一篇 2021年5月31日 下午9:31

相关推荐

发表回复

登录后才能评论