• 多线程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);
    
        }
  • 相关阅读:
    Windows SDK编程(Delphi版) 之 应用基础,楔子
    一个小问题引发的论证思考
    Delphi 组件开发教程指南(7)继续模拟动画显示控件
    用PyInstaller将python转成可执行文件exe笔记
    使用 .Net Memory Profiler 诊断 .NET 应用内存泄漏(方法与实践)
    Microsof Office SharePoint 2007 工作流开发环境搭建
    How to monitor Web server performance by using counter logs in System Monitor in IIS
    LINQ之Order By
    window 性能监视器
    内存泄露检测工具
  • 原文地址:https://www.cnblogs.com/xwx20160804/p/14467535.html
Copyright © 2020-2023  润新知