一. 问题思考
1.CAS涉及到用户模式到内核模式的切换吗?
CAS机制的英文缩写是Compare and Swap,翻译一下就是比较和交换
CAS机制中使用3个基本操作数:内存地址V,旧的预期值A,要修改的新值B,更新一个变量的时候,只有当变量的旧的预期值A和内存地址V中的值相同的时候,才会将内存地址V中的值更新为新值B
Compare和Swap过程的原子性是通过unsafe类来实现的,unsafe类为我们提供了硬件级别的原子操作!
不涉及内核模式的切换
2.为什么说创建Java线程的方式本质上只有一种?Java线程和go语言的协程有什么区别?
最终都是new Thread()实现
3.如何优雅的终止线程?
通过线程中断命令
设置标记位
Thread.currentThread().interrupt()
在线程内通过判断是否存在中断标志
Thread.currentThread().isInterrupted()
public static void main(String[] args) { System.out.println("begin"); Thread t1 = new Thread(new Runnable() { @Override public void run() { while (true) { i++; System.out.println(i); //Thread.interrupted() 清除中断标志位 //Thread.currentThread().isInterrupted() 不会清除中断标志位 if (Thread.currentThread().isInterrupted()) { System.out.println("说明有线程中断标志,可以跳出线程或执行对应逻辑"); } if(i==10){ break; } } } }); t1.start(); //不会停止线程t1,只会设置一个中断标志位 flag=true t1.interrupt(); }
4.Java线程之间如何通信的,有哪些方式?
volatile wait() notify() notifyAll() LockSupport.park LockSupport.unpark
二.线程有那几种状态
要分多种层面
操作系统层面:
JAVA层面:
1. NEW(初始化状态)
2. RUNNABLE(可运行状态+运行状态)JAVA已经将线程交给操作系统执行,是否真正已执行,并不能由JAVA管理
3. BLOCKED(阻塞状态)
4. WAITING(无时限等待)
5. TIMED_WAITING(有时限等待)
6. TERMINATED(终止状态)
三.线程相关
1.Java线程执行为什么不能直接调用run()方法,而要调用start()方法?
run方法此时只是一个对象的方法,如果直接调用,是由当前线程去执行,而不是新线程
start()此时才是真正去创建一个新线程(去操作系统申请创建线程)
2.Java线程属于内核级线程?
JDK1.2——
基于操作系统原生线程模型来实现。Sun JDK,它的Windows版本和Linux版本
都使用一对一的线程模型实现,一条Java线程就映射到一条轻量级进程之中。
内核级线程(Kernel Level Thread ,KLT
):它们是依赖于内核的,即无论是用户进程中的线
程,还是系统进程中的线程,它们的创建、撤消、切换都由内核实现。
用户级线程(User Level Thread,ULT)
:操作系统内核不知道应用线程的存在。
四.Thread常用方法
sleep
1.调用sleep方法,线程会从running状态修改为
TIMED_WAITING,不会释放对象锁
2.其他线程调用线程中断方法interrupt, 当前线程会抛出InterruptedException,并且会清除中断标
志
3.睡眠结束后未必会立即执行
4.如果sleep(0)传入的是0等同于yield
yield
1.调用yield方法会从running(运行)状态改为runnable(就绪)状态,给其他高优先级线程执行,不会释放对象锁
2.假设只有一个线程线程,又会立即执行
3.具体实现是基于操作系统
join
1.
join()
方法将挂起调用线程的执行,直到被调用的对象完成它的执行
例子:线程2要等线程1先执行完,线程3要等线程2执行完
public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.println("thread1")); Thread thread2 = new Thread(() -> { try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thread2"); }); Thread thread3 = new Thread(() -> { try { thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thread3"); }); thread1.start(); thread2.start(); thread3.start(); }
等待唤醒(等待通知)机制
等待唤醒机制可以基于wait和notify方法来实现,在一个线程内调用该线程锁对象的wait方法,
线程将进入等待队列进行等待直到被唤醒
notify 不能指定线程
notifyall 会唤醒对象下全部线程
LockSupport是JDK中用来实现线程阻塞和唤醒的工具,线程调用park则等待“许可”,调用
unpark则为指定线程提供“许可”。
使用它可以在任何场合使线程阻塞,可以指定任何线程进行
唤醒,并且不用担心阻塞和唤醒操作的顺序,但要注意连续多次唤醒的效果和一次唤醒是一样
的
wait和sleep的区别?
wait是object的方法 sleep是Thread的方法
wait必须在同步块中使用
wait会释放对象锁