线程是操作系统调度的最小单元,多线程同时执行,可以提高程序性能 。
操作系统运行一个程序,就会创建一个进程,在一个进程里可以创建多个线程,因此线程也叫做轻量级进程 。
现代处理器都是多核的,程序运行过程中能够创建多个线程,而一个线程在一个时刻只能运行在一个处理器核心上,如果一个单线程程序在运行时只能使用一个处理器核心,那么再多的处理器核心加入也无法显著提升该程序的执行效率。
线程优先级决定线程需要多或者少分配一些处理器资源的线程属性
设置线程优先级时,针对频繁阻塞(休眠或者I/O操作)的线程需要设置较高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。
程序正确性不能依赖于优先级高低 —— 不同操作系统有不同的处理方式
New 初始态\ Running 运行态 \ Blocked 阻塞态 \Waiting 等待态\ TimeWaiting 超时等待态\ Terminated 终止态
注: Java将操作系统中的运行和就绪两个状态合并称为运行状态
阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态,但是阻塞在java.concurrent包中Lock接口的线程状态却是等待状态,因为java.concurrent包中Lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。
支持型线程,用作程序中台调度以及支持性工作
当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出
新构造的线程对象是由其parent线程来进行空间分配的,child线程继承了parent是否为Daemon、优先级和加载资源的contextClassLoader以及可继承的ThreadLocal,同时还会分配一个唯一的ID来标识这个child线程,至此,一个能够运行的线程对象就初始化好了。
start()方法的含义是:当前线程(即parent线程)同步告知Java虚拟机,只要线程规划器空闲,应立即启动调用start()方法的线程
告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。
关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。
等待/通知机制是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。
等待/通知的相关方法是任意Java对象都具备的,因为这些方法被定义在所有对象的超类java.lang.Object上。
synchronized(对象) {
while(条件不满足) {
对象.wait();
}
对应的处理逻辑
}
synchronized(对象) {
改变条件
对象.notifyAll();
}
线程A执行了thread.join()语句,其含义是:当前线程A等待thread线程终止之后才从thread.join()返回
join() 当线程终止时,会调用线程自身的notifyAll()方法,会通知所有等待在该线程对象上的线程。
以ThreadLocal对象为键、任意对象为值的存储结构,一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。
ThreadLocal 调用耗时统计的功能上,在方法的入口前执行begin()方法,在方法调用后执行end()方法,好处是两个方法的调用不用在一个方法或者类中,比如在AOP(面向方面编程)中,可以在方法调用前的切入点执行begin()方法,而在方法调用后的切入点执行end()方法,这样依旧可以获得方法的执行耗时。
场景:调用一个方法时等待一段时间0,如果该方法能够在给定的时间段之内得到结果,那么将结果立刻返回,反之,超时返回默认结果。
解决:对象加锁 条件循环 处理逻辑 + 设置超时时间段
应用:超时等待模式可以用来实现 数据库连接池 中数据库连接操作超时返回
好处: 保证客户端线程不会一直挂在连接获取的操作上,而是“按时”返回,并告知客户端连接获取出现问题,是系统的一种自我保护机制,针对昂贵资源(比如数据库连接)的获取都应该加以超时限制。
为什么需要考虑 C/S 架构的程序,如果没有线程池, 我们客户端向服务器发的请求,每个请求创建一个线程,假设我们有 1 万个请求, 那么就需要创建 1 万的线程进行处理。 众所周知,线程的创建和上下文切换是非常消耗资源的。因此, 需要线程池技术解决这个问题 。
线程池好处