zoukankan      html  css  js  c++  java
  • 多线程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);
    
        }
  • 相关阅读:
    文件操作
    通过类型断言获取error类型,获得更详细的信息

    数组
    使用unsafe改善性能
    使用unsafe.Pointer将结构体转为[]byte
    (GoRails)链接link_to到当前页current Page 并使用参数 (类ActionController::Parameters)
    用ActionController::Renderer的render方法渲染模版
    innerHTML用法及错误:无法设置未定义或null引用的属性“innerHTML”解决
    ActionCable的部署(参考Gorails)
  • 原文地址:https://www.cnblogs.com/xwx20160804/p/14467535.html
Copyright © 2011-2022 走看看