多线程1--基础知识

什么是进程,线程?

提高对cpu的利用率

1.进程是什么?

--资源分配的基本单位--静态单位

2.线程是什么?

--调度执行的基本单位--动态单位

3.纤程/协程什么?

 

线程数是不是越大越好?

答案肯定是否定的

首先简单说明下计算机底层原理,cpu分为:ALU,寄存器组(数据),PC(执行到哪条指令)

根据OS线程调度算法,当一个线程执行完切换到另一个线程时(T1,T2),T1(指令和数据放到缓存),T2(指令和数据放到cpu),这是一个循环的操作,cpu只进行切换,OS进行调度.

线程切换.IO等都会消耗资源,所以当你线程太多的时候会消耗大量的资源

 

下面我们看一个列子

 private static double[] nums = new double[1_0000_0000];
    private static Random r = new Random();

    private static DecimalFormat df = new DecimalFormat("0.00");

    static {
        for (int i = 0; i < nums.length; i++) {
            nums[i] = r.nextDouble();
        }
    }


    private static void m1() {
        long start = System.currentTimeMillis();
        double result = 0.0;
        for (int i = 0; i < nums.length; i++) {
            result += nums[i];
        }
        long end = System.currentTimeMillis();
        System.out.println("m1 time:" + (end - start) + " result:" + df.format(result));
    }

    static double result1 = 0.0, result2 = 0.0, result = 0.0;

    private static void m2() throws Exception {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < nums.length / 2; i++) {
                result1 += nums[i];
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = nums.length / 2; i < nums.length; i++) {
                result2 += nums[i];
            }
        });
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        result = result1 + result2;
        long end = System.currentTimeMillis();
        System.out.println("m2 time:" + (end - start) + " result:" + df.format(result));
    }


    private static void m3() throws Exception {
        //threadCount=cpuCount*Ucpu(期望利用率)*(1+w/c)(等待时间/计算时间)
        final int threadCount = 10000;
        Thread[] threads = new Thread[threadCount];
        double[] results = new double[threadCount];
        final int segmentCount = nums.length / threadCount;
//        CountDownLatch latch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            int m = i;
            threads[i] = new Thread(() -> {
                for (int j = m * segmentCount; j < (m + 1) * segmentCount && j < nums.length; j++) {
                    results[m] += nums[j];
                }
            });
//            latch.countDown();
        }

        double result = 0.0;
        long start = System.currentTimeMillis();
        for (Thread t : threads) {
            t.start();
        }
        for (Thread t : threads) {
            t.join();
        }
//        latch.await();
        for (int i = 0; i < results.length; i++) {
            result += results[i];
        }
        long end = System.currentTimeMillis();
        System.out.println("m3 time:" + (end - start) + " result:" + df.format(result));
    }

    public static void main(String[] args) throws Exception {
        m1();
        m2();
        m3();
    }

m1,m2,m3三个方法,我先简单介绍下

m1:傻瓜式单线程相加

m2:两个线程分别计算,然后相加

m3:一万个线程,分别计算,然后相加

下面我们看下结果

 

 这里可以看到m3居然是m1的6倍,可见并不是线程数越大越好.

那么问题来了,到底多少线程合适呢?

有一个公式:

threadCount=cpuCount*Ucpu(期望利用率)*(1+w/c)(等待时间/计算时间)
这和我们的cpu数量是有一定关系的,套用这个公式我们可以有一定的依据去设定.
注意这个公式并不是完全适用的,因为实际情况下我们一个机器上是有很多线程被占用的,并不是跑我们这个程序,比如系统进程等等.
所以我们一般有两种方法可以去设定这个线程数
  • 压测:通过压测去找到最适合的线程数

 

线程启动的方式

一共5中,我们下面看下列子

  static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello MyThread");
        }
    }

    static class MyRun implements Runnable {

        @Override
        public void run() {
            System.out.println("Hello MyRun");
        }
    }

    static class MyCall implements Callable<String> {

        @Override
        public String call() throws Exception {
            System.out.println("Hello MyCall");
            return "MyCall";
        }
    }

    public static void main(String[] args) throws Exception {
        new MyThread().run();//非新线程
        new MyThread().start();
        new Thread(new MyRun()).start();
        new Thread(() -> {
            System.out.println("Hello Lambda");
        });
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            System.out.println("Hello MyThreadPool");
        });
        Future<String> result = executorService.submit(new MyCall());
        System.out.println("result:" + result.get());

        executorService.shutdown();

        FutureTask<String> futureTask = new FutureTask<>(new MyCall());
        new Thread(futureTask).start();
        String futureTaskResult = futureTask.get();
        System.out.println("futureTaskResult:" + futureTaskResult);

    }

 

posted @ 2021-03-03 18:18  xwx唐宋元明清  阅读(54)  评论(0编辑  收藏  举报