最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
if (mills<=0){
lock();
}else {
long hasRemain = mills;
long endTime = System.currentTimeMillis()+mills;
while (initValue){
if (hasRemain<=0)
throw new TimeOutException(“Time out”);
blockThreadCollection.add(Thread.currentThread());
hasRemain = endTime-System.currentTimeMillis();
}
this.initValue = true;
currenThread = Thread.currentThread();
}
}
@Override
public synchronized void unlock() {
if (currenThread==Thread.currentThread()){
this.initValue = false; //表明锁已经释放
Optional.of(Thread.currentThread().getName()+ " release the lock monitor").ifPresent(System.out::println);
this.notifyAll();
}
}
@Override
public Collection getBlockedThread() {
return Collections.unmodifiableCollection(blockThreadCollection);
}
@Override
public int getBlockSize() {
return blockThreadCollection.size();
}
}
public class BlockTest {
public static void main(String[] args) throws InterruptedException {
final BooleanLock booleanLock = new BooleanLock();
// 使用Stream流的方式创建四个线程
Stream.of(“T1”,“T2”,“T3”,“T4”).forEach(name->{
new Thread(()->{
try {
booleanLock.lock(10);
Optional.of(Thread.currentThread().getName()+" have the lock Monitor").ifPresent(System.out::println);
work();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Lock.TimeOutException e) {
Optional.of(Thread.currentThread().getName()+" time out").ifPresent(System.out::println);
} finally {
booleanLock.unlock();
}
},name).start();
});
}
//如果是需要一直等待就调用 lock(),如果是超时要退出来就调用超时lock(long millo)
private static void work() throws InterruptedException{
Optional.of(Thread.currentThread().getName()+" is working…'").ifPresent(System.out::println);
Thread.sleep(40_000);
}
}
运行:
T1 have the lock Monitor
T1 is working…
T2 time out
T4 time out
T3 time out
2.按顺序加锁
按照顺序加锁是一种有效防止死锁的机制,但是这种方式,你需要先知道所有可能用到锁的位置,并对这些锁安排一个顺序
3.死锁检测
死锁检测是一个更好的死锁预防机制,主要用于超时锁和按顺序加锁不可用的场景每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph 等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。
如果检测出死锁,有两种处理手段:
-
释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁,原因同超时类似,不能从根本上减轻竞争.
-
一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。
2.活锁(Livelock)
==================
什么是活锁
死锁是一直死等,活锁他不死等,它会一直执行,但是线程就是不能继续,因为它不断重试相同的操作。换句话说,就是信息处理线程并没有发生阻塞,但是永远都不会前进了,当他们为了彼此间的响应而相互礼让,使得没有一个线程能够继续前进,那么就发生了活锁
避免活锁
========
解决“活锁”的方案很简单,谦让时,尝试等待一个随机的时间就可以了。由于等待的时间是随机的,所以同时相撞后再次相撞的概率就很低了。“等待一个随机时间”的方案虽然很简单,却非常有效,Raft 这样知名的分布式一致性算法中也用到了它。
3.饥饿
========
什么是饥饿
高优先级线程吞噬所有的低优先级线程的 CPU 时间。线程被永久堵塞在一个等待进入同步块的状态,因为其他线程总是能在它之前持续地对该同步块进行访问。线程在等待一个本身(在其上调用 wait())也处于永久等待完成的对象,因为其他线程总是被持续地获得唤醒。
饥饿问题最经典的例子就是哲学家问题。如图所示:有五个哲学家用餐,每个人要活得两把叉子才可以就餐。当 2、4 就餐时,1、3、5 永远无法就餐,只能看着盘中的美食饥饿的等待着。
解决饥饿
========
Java 不可能实现 100% 的公平性,我们依然可以通过同步结构在线程间实现公平性的提高。
有三种方案:
保证资源充足公平地分配资源避免持有锁的线程长时间执行
这三个方案中,方案一和方案三的适用场景比较有限,因为很多场景下,资源的稀缺性是没办法解决的,持有锁的线程执行的时间也很难缩短。倒是方案二的适用场景相对来说更多一些。
那如何公平地分配资源呢?在并发编程里,主要是使用公平锁。所谓公平锁,是一种先来后到的方案,线程的等待是有顺序的,排在等待队列前面的线程会优先获得资源。
4.性能问题
==========
并发执行一定比串行执行快吗?线程越多执行越快吗?
答案是:并发不一定比串行快。因为有创建线程和线程上下文切换的开销。
最后
既已说到spring cloud alibaba,那对于整个微服务架构,如果想要进一步地向上提升自己,到底应该掌握哪些核心技能呢?
就个人而言,对于整个微服务架构,像RPC、Dubbo、Spring Boot、Spring Cloud Alibaba、Docker、kubernetes、Spring Cloud Netflix、Service Mesh等这些都是最最核心的知识,架构师必经之路!下图,是自绘的微服务架构路线体系大纲,如果有还不知道自己该掌握些啥技术的朋友,可根据小编手绘的大纲进行一个参考。
如果觉得图片不够清晰,也可来找小编分享原件的xmind文档!
且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:
-
出神入化——SpringCloudAlibaba.pdf
-
SpringCloud微服务架构笔记(一).pdf
-
SpringCloud微服务架构笔记(二).pdf
-
SpringCloud微服务架构笔记(三).pdf
-
SpringCloud微服务架构笔记(四).pdf
-
Dubbo框架RPC实现原理.pdf
-
Dubbo最新全面深度解读.pdf
-
Spring Boot学习教程.pdf
-
SpringBoo核心宝典.pdf
-
第一本Docker书-完整版.pdf
-
使用SpringCloud和Docker实战微服务.pdf
-
K8S(kubernetes)学习指南.pdf
另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!
另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!
[外链图片转存中…(img-NUBOvkSC-1715145296518)]