系列文章目录
多线程和高并发(一) Thread
多线程和高并发(二) volatile关键字
多线程和高并发(三) Compare And Swap
多线程和高并发(四) 线程间通信
多线程和高并发(五) ThreadLocal & Lock
多线程和高并发(六) ReentrantLock
多线程和高并发(七) 线程池
文章目录
进程
狭义上理解:是运行在电脑中的一个程序,一个进程包含多个线程,再操作系统中是以进程来分配虚拟存储空间,文件描述符等。
线程
是进程的一个执行单元,每个线程都有自己的线程栈,自己的寄存器环境,自己的线程本地存储。
主线程和子线程
JVM启动时候会创建一个线程执行main方法,所以main方法所在的线程是主线程,线程之间不独立,例如在主线程创建线程A,A即为主线程的子线程。
串行,并发,并行
三者传输速度为:串行 <= 并发 <= 并行
并发:是一个核心运行多个线程,看似一起运行,其实是切换运行不同线程
并行:是多个核心同时分别执行线程。
串行:是一个核心按顺序执行线程。
线程的创建与启动
创建:创建一个线程就是new一个Thread,其中Thread实现了Runable接口
启动:使用Thread静态方法start()启动线程
注意
执行start()不代表立马启动了线程,因为线程发放需要等JVM调配,
多线程运行结果与代码执行顺序或调用顺序无关 ,
线程启动后,会执行run方法。
线程常用方法
currentThread()方法
获取当前线程对象,是Thread的静态方法;
Thread.currentThread();
setName()/getName() 方法
设置/获取当前进程的线程名称。
isAlive()方法
实例方法,返回Boolean值,判断当前线程是否处于活动状态,线程关闭也需要一段时间。
sleep()方法
静态方法,让执行sleep的线程休眠指定毫秒数,线程转为TIMED_WAITING状态
getId()方法
获取当前线程的ID,如果线程结束,ID可能会被复用。
yield()线程让步方法
静态方法,使用此方法的线程,会主动放弃使用cpu资源,线程转为READY状态,直到再次有空闲CPU,自动转为RUNNING状态。
@Override
public void run() {
long begin = System.currentTimeMillis();
long sum = 0;
for (int i = 1; i <= 1000000; i++) {
sum += i;
//线程让步, 放弃 CPU 执行权
Thread.yield();
}
long end = System.currentTimeMillis();
System.out.println("用时: " + (end - begin));
}
isPriority()方法
设置线程执行优先级,优先级越高,可能优先执行,默认是5,取值范围1-10,10最高。
优先级具有继承性,子线程会继承父线程的优先级。
interrupt()方法
实例方法,中断线程方法,配合isinterrupted()方法使用;
public class SubThread2 extends Thread {
@Override public void run() {
super.run();
for(int i = 1; i <= 10000; i++){
//判断线程的中断标志,线程有 isInterrupted()方法,该 方法返回线程的中断标志
if ( this.isInterrupted() ){
System.out.println("当前线程的中断标志为 true, 我要退出了");
// break; //中断循环, run()方法体执行完毕, 子线程运行完毕
return; //直接结束当前 run()方法的执行
}
System.out.println("sub thread --> " + i);
}
}
}
setDaemon()守护线程方法
线程分为用户线程和守护线程;
参数值为true,设置线程为守护线程,如果没有用户线程,守护线程会自动销毁,GC就是一个守护线程。
多线程生命周期
线程生命周期可以通过线程实例方法的getState()方法获取,返回值是一个枚举;
NEW:新建状态,创建线程对象,执行start方法之前。
RUNNABLE:可运行状态,是一个复合状态
- READY:start()方法之后,JVM线程调度分配之前,可以使用yield方法将RUNNING状态 转为READY状态
- RUNNING:JVM线程调度分配后,READY转为RUNNING状态,该状态表示正在执行。
BLOCKED:阻塞状态,线程发起阻塞I/O操作,锁被其它线程占有,这个时候被操作系统挂起,处于阻塞状态不会占用CPU资源,当阻塞执行完成,会自动转为RUNNABLE状态,阻塞状态的线程,即使调用interrupt()方法也不会改变其状态。
WAITING:等待状态,执行了object.wait(),thread.join()等无时间限制的方法,线程会转为WAITING状态,WAITING状态执行了object.notify()方法,或者加入的线程执行完毕,当前线程会转为RUNNABLE状态,处于WAITING状态的线程不会被分配CPU资源且不持有锁。
TIMED_WAITING:有限时间等待状态,线程执行了有限等待时间方法,例如thread.sleep(500)方法,当前时间过去后线程会转为RUNNABLE状态。
TERMINATED:终止状态,线程执行完run方法,结束处于终止状态(这是java线程状态,操作系统可能会复用线程或者注销线程)。
多线程编程的优势与存在的风险
多线程编程优势:
- 提高系统的吞吐量
- 提高响应速度
- 充分利用多核(Multicore)CPU资源
多线程编程风险和问题:
- 线程安全问题:可能会产生脏读,数据丢失
- 线程活性问题:程序自身缺陷或者资源稀缺,导致线程一直处于非RUNNABLE状态
- 死锁(Deadlock):类似鹬蚌相争
- 锁死(Lockout):类似钥匙毁坏了
- 活锁(Starvation):类似强者恒强,而弱者抢不到资源
- 上下文切换:处理器一个线程切换到另一个线程。
失 - 线程活性问题:程序自身缺陷或者资源稀缺,导致线程一直处于非RUNNABLE状态
- 死锁(Deadlock):类似鹬蚌相争
- 锁死(Lockout):类似钥匙毁坏了
- 活锁(Starvation):类似强者恒强,而弱者抢不到资源
- 上下文切换:处理器一个线程切换到另一个线程。
- 可靠性:可能因为一个线程导致JVM意外终止