多线程基本概念

进程和线程分别是什么线程

进程是资源分配的基本单位
线程是执行的基本单位,多个进程之前可以共享进程的资源

cpu

cpu只做计算
如果发生线程切换 则需要操作系统进行调度。

线程的切换

  1. 单核cpu设置多线程是否有意义

有意义
因为不是所有任务都消耗cpu,比如等待网络响应。
这时候可以把cpu让出来让另一条线程继续进行cpu运算。

  1. 线程数是不是越多越好

不是,因为线程切换存在消耗,如我开10000 个线程 程序就会在线程里来回切换,反而降低了效率。

线程池 设置多少个线程比较合适

这取决于 线程里的操作,多久在计算,多久在进行网络io等待。
需要注意一点,如果这台机器上不止一个应用,那么要考虑其他机器也需要用到线程,操作系统也需要用到线程,所以得均衡考虑。
以下是公式
具体 需要wait 多久 这完全取决于你各个行为的并发数等,这个初期无法预估,得通过统计,可以通过profiler推算。
image-1650696190297

线程的5种创建方式

  1. 继承thread
  2. 实现Runnable接口

继承thread和实现Runnable接口哪个更好?

实现Runnable接口更好,因为实现runnable 接口,还可以实现别的接口,而继承不行所以runnable 更灵活

  1. 使用lambda (和new Thread()其实是一样的)
  2. 线程池,其实就是管理Thread 的池子,防止线程数过多。
  3. 实现Callable 和Runnable 的区别是,Callable 是一个带返回值的模型。Callable 会返回Future对象,Future.get 可以堵塞等待线程执行完毕。
 ExecutorService executor = Executors.newCachedThreadPool();
 		// 线程池接收一个Callable,将返回值存储到Future对象中
        var future = executor.submit(() -> {
            System.out.println("callable done");
            return 1;
        });
        Thread.sleep(10000);
        // 如果线程执行完毕,则直接返回,如果未执行完毕则阻塞到线程返回。
        System.out.println(submit.get());

由于new Thread() 不能直接传callable 所以得通过一层转换,代码如下。

new Thread( new FutureTask(() -> {
                System.out.println("callable done");
                return 1;
            }));