多线程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); }