-
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块之后才能执行该代码块
-
然而,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块
-
尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其他synchronized(this)同步代码块的访问将被阻塞。
-
第三个例子同样使用与其他同步代码块,他就获得了这个object的对象锁。结果,其他线程对该object对象所有同步代码块部分的访问都被暂时阻止
-
以上规则对其他对象锁同样适用。
下面是代码例子,当有线程在注册的时候获取到该单例对象的锁, 则在当前线程注册完成之前其他线程无法进行查询学生总数量, 因为获取该对象的同步锁需要等待。反之亦然。
/**
* 采用Spring默认的事务提交方式:发生运行时异常回滚,发生受查异常提交
* @param student
* @throws Exception
*/
@CacheEvict(value = "realTimeCache", allEntries = true)
@Transactional(rollbackFor = Exception.class)
@Override
public void addStudent(Student student) throws Exception {
synchronized (this) {
dao.insertStudent(student);
}
}
/**
* redis在高并发情况下可能会存在那些问题
* 缓存击穿 某个key在高并发的时候过期了,大量缓存打到数据库,使用双重检测锁
* 缓存雪崩 大面积的key过期
* 缓存穿透 当从db中查询结果为null时
* @return
*/
@Override
public Integer findStudentCount() {
// 获取redis操作对象
BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
// 从redis中获取指定key的value
Object count = ops.get();
// 双重检测 (可能是过期,也可能是没有值)
if (count == null) {
synchronized (this) {
count = ops.get();
if (count == null) {
count = dao.findStudentCount();
ops.set(count, 10, TimeUnit.SECONDS);
}
}
}
return (Integer) count;
}