一:在多线程中用到锁的地方非常少。因为没有什么共享的地方需要用到锁
锁就是要用在共享的数据上面。属于单例的数据。如果是多例的数据,则不存在会乱的情况。
举例:在多个线程同时写同时去写日志文件的时候,会写乱。只是没有顺序可言。
加锁的方式:1- synchronized ;2- lock接口
用锁的多线程场景一般分 2 种:
- 在tomcat的线程池多线程中(我的意思是说针对每次客户请求在你业务的时候使用锁,例如电商项目的超卖超扣 / 项目接口的幂等性)
- 多线程的通信,这种场景的线程都是跟随主线程(app程序)的生命周期死亡。生产-消费 模式
二:一般使用最多的就是synchronized关键字锁,因为不用自己担心死锁的情况,也不用自己去释放锁,而且颗粒度也可以很小
- 锁的颗粒度是指你这个锁对象形态范围,例如synchronized(this) / synchronized(class)
- 亦或者 lock 锁的粒度,lock的锁的粒度,一般很少有人控制的很小,都是在类的属性最上面定义个lock(可以使用其他方式中转则可以达到 synchronized 或更小粒度,这里不再赘述)
例如:
public class AbsSubjectServiceImpl extends AbsSubjectService<CmsSubjectDTO,CmsSubjectDTO>{
static Lock lock = new ReentrantLock();
@Override
public List<CmsSubjectDTO> selectSubjectList(CmsSubjectDTO cmsSubjectDTO) {
return null;
}
}
三:ThreadLocal也是一个很关键的类。在多线程,或者是多进程中都会使用到
private final static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
// private final static ThreadLocal<User> userThreadLocal = new InheritableThreadLocal<>();
/**
* 设置当前用户
*/
public void setCurrentUser(User user) {
userThreadLocal.set(user);
}
/**
* 从本地线程中取当前用户
*/
public User getCurrentUser() {
User user = userThreadLocal.get();
if (null == user) {
user = (User) SecurityUtils.getSubject().getPrincipal();
}
return user;
}
以上就是我用 ThreadLocal 对象作为实际项目中的使用。相当于一次请求(tomcat线程)的一次上下文,在没使用 remove() 方法之前都是可以一直获取到。
注意:使用 ThreadLocal 时候,如果是单次线程使用线程会自己销毁,可以不需要 remove() 方法,如使用的是线程池方式控制线程,则使用 ThreadLocal 对象时候,一定要记得 在最后 remove() 掉,不然线程池的复用机制会导致 ThreadLocal 中数据错乱;
后感:我一般喜欢成为 ThreadLocal 为上下文
- 其实在spring 中 HttpServletRequest 每次请求的内容都互不影响都是 靠 ThreadLocal 对象保护着。详情可看 spring - RequestContextHolder 类。包括spring的WebApplicationContextUtils对象拿取HttpServletRequest 也是通过 RequestContextHolder 类拿取的。互通的,这里不再赘述
- 在安全框架 shiro / spring security 保存用户的信息也是使用 ThreadLocal 对象。