文章目录
- 1. 如何停止正在运行的线程
- 2. 请你谈谈JMM(java内存模型)
- 3. AQS
- 4. ReentrantLock实现原理
- 5. 死锁怎么检测
1. 如何停止正在运行的线程
- 设置一个共享变量作为线程退出的标记,当这个标记不满足时while循环,线程一直运行,另一个线程将这个共享变量设置为真,当然要保证两个线程间的可见性的话要加volatile,那这个一直运行的线程while不成立就会退出了,也就停止了
- interrupt打断线程,对于阻塞的线程的话(sleep、wait、join)会抛出异常,对于正常的线程的话我们判断打断标记,为ture的话表示被打断了,这时候break就能退出线程。
2. 请你谈谈JMM(java内存模型)
JMM定义了对我们定义的一些共享变量的访问的规则吧,其实就是在多线程的环境下怎么去正确的读写这些共享变量,JMM呢就提供了这种安全的保障,其实每一个线程都在自己的工作内存中去操作,工作内存中就是主存中的这些共享变量的副本,那就保证了当前这个线程的操作的正确性,但是要保证我们操作了工作内存后和主存数据的一致性,像volatile吧就其实也保证了别的线程读到了也是正确的 。
3. AQS
AQS,它是一种在并发的环境下的这种安全的队列吧,是一个并发的基础的一个框架吧,提供了这种锁的机制,像它也支持多个条件变量,条件不满足进入,以及这个先进先出的队列,争抢不到就会进入,内部的话其实它是一个双向链表,state属性呢就表示当前有没有获得锁,其实也是基于CAS机制实现的,像在Java中,它的子类的话ReentrantLock、Countdownlatch、信号量啊都是基于AQS实现的。
4. ReentrantLock实现原理
主要利用CAS+AQS实现
ReentrantLock 里面的加锁啊解锁啊这些其实都是调用AQS里面的相关的方法的,像加锁lock方法,AQS又有不同的实现比如说公平的非公平的,首先它会以CAS方式修改state状态,如果修改成功那就表示加锁成功,将Owner线程设置为当前这个线程,如果加锁失败,就会创建一个Node对象然后加入到队列中去,这个队列其实是一个双向链表,并且再将Node加入到队列的这部分代码中,它是一直循环的是一个死循环,它会记录当前节点的前驱节点,自己呢(线程)就park住,也就实现了加锁。解锁呢也是一样,也是调用AQS中的方法,将state设置为0,将owner线程设置为null,然后unpark恢复头节点后面的线程就是唤醒一个嘛,那这个线程就能接着在park住的位置继续执行,它是在一个死循环里面,然后又循环再获取锁,修改state状态修改owner线程。