进程是申请资源的基本单位,线程是cpu 时间片的基本单位。
一、cpu 核心与线程数
目前一个 cpu 上可以有多个核心,cpu 上一个核心可以对应一个线程。
Intel 的 超线程技术,可以实现 1 个cpu 核心对应 2 个逻辑处理器。所以在 windows上你查看性能的时候,发现只有 4 核心,但是有 8 个逻辑处理器。
二、线程轮转
1.6G 的 CPU 执行一条指令一般在 0.6ns (0.6纳秒)级别,所以是非常快的。但是线程的上下文切换时非常耗时的,一般耗时在 2W 个 CPU 周期级别。
三、并行 和 并发
并行就是同时进行,比如,有 2 个咖啡机,就可以同时 2 个人并行打咖啡
并发:说并发,一定是有时间单位的,会有并发量的说法。所以基于上面的例子来说,只有一台咖啡机,大家轮着来,这时候就有类似 这个咖啡机每小时的并发量是 10,就是给10个人提供服务。
四、高并发的意义
充分利用硬件资源。比如有四核,但是你只有一个线程
用户响应。比如商城 App ,下单之后,会给快递发送消息,给用户发送短信等等,这些其实都是互相独立的,不用单线程进行
但是,多线程不一定快,因为有竞争锁的过程,可能比单线程还慢
OS 对线程数总数是有限制的,比如 Linux 1000个,windows 2000 个
线程都会有栈空间的,所以线程数量太多的话,空间占用都很可观
句柄和文件描述符也都有数量上限
Java 程序天生就是多线程的,比如,你写个main方法,简单写几行代码,比如下面的代码:
1 | public static void main(String[] args) throws Exception{ |
上面的 ThreadMXBean就是用来查看当前虚拟机所有的线程的,我们可以看到有多个线程在运行,运行的结果可能会如下所示:
[1]main
[8]Reference Handler
[9]Finalizer
[10]Signal Dispatcher
[11]Attach Listener
[17]Common-Cleaner
[18]Monitor Ctrl-Break
[19]Notification Thread
其中 main 线程我们能理解,就是我们的主线程; Finalizer 方法也好理解,因为 Object 类中有个 finalize() 方法,我们在学习 GC 的时候了解过,如果对象不可达,但是重写了 finalize() 方法还没执行的话,会交给一个 低优先级(守护)线程去执行,但是不保证 finalize() 方法执行完成。说的就是这个 Finalizer 线程。
五、开启新线程的方式
到底有几种方式,其实挺纠结的,那么我们就以 Java 的 Thread.java 类的官方文档来看:
There are two ways to create a new thread of execution
上面说的就是 2 种:
扩展 Thread 类(继承一下Thread),重写 run 方法。
Runnable 接口。比如: UserRunnable implements Runnable,之后,在 new Thread的时候,将这个 UserRunnable 作为参数传进去
类似 Callable 之类的其实就是 Runnable 接口来实现新线程的。
Thread 和 Runnable 二者的区别
Thread 是 Java 对线程的抽象,而 Runnable 是对任务的抽象
六、线程的停止
stop 、destroy suspend 、resume 等线程方法已经被废弃了,因为他们停止的时候,不一定正常释放资源。比如要写文件 10k ,但是才写了 4k,就stop 了。
但是 interrupt 方法可以作为我们停止线程的一个方法。