两类锁:
一、独占锁:redis的分布式锁、ReentrantLock锁;
二、共享锁:synchronized的对象锁
今天针对高并发下的共享锁做一点心得分享,举例:
银行卡取钱的两个场景:
场景一:假设现在有10个人在同一家银行的10张不同的银行卡上取钱,在程序执行层面肯定是要允许10个人同时取,而不是要10个人排队取;
场景二:假设现在有2个人取同一张银行卡上的钱,在程序执行层面肯定是要排队执行取钱的操作,而不能同时执行取钱的操作;
那么问题来了,这两种场景都是取钱,那么我们的锁要在什么情况下使用,才能达到目的并且是性能最优化呢?
1、独占锁:可以达到我们的目的,但是却不能使程序性能最优化,因为独占锁是锁定的程序,所有人取钱都需要排队;
2、共享锁:我们使用synchronized关键词对银行账户上锁,允许多个不同账户同时做取钱操作,但多个人对同一个账户做取钱操作时必须要排队,具体代码如下:
private void repeatCall(String key){
System.out.println("[在外面]"+key);
synchronized(key.intern()){
System.out.println("[进来了]"+key);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
key.intern():重点解释:
字符串是存储在常量池中的,有两种类型的字符串数据会存储在常量池中:
(1)编译期就可以确定的字符串,即使用""引起来的字符串,比如String a = "123"、String b = "1" + B.getStringDataFromDB() + "2" + C.getStringDataFromDB()、这里的"123"、"1"、"2"都是编译期间就可以确定的字符串,因此会放入常量池,而B.getStringDataFromDB()、C.getStringDataFromDB()这两个数据由于编译期间无法确定,因此它们是在堆上进行分配的
(2)使用String的intern()方法操作的字符串,比如String b = B.getStringDataFromDB().intern(),尽管B.getStringDataFromDB()方法拿到的字符串是在堆上分配的,但是由于后面加入了intern(),因此B.getStringDataFromDB()方法的结果,会写入常量池中
常量池中的String数据有一个特点:每次取数据的时候,如果常量池中有,直接拿常量池中的数据;如果常量池中没有,将数据写入常量池中并返回常量池中的数据。