对于共享的、可变的数据的访问造成了并发安全性问题

如何避免,几种思路:

  • 加锁,使得共享数据的访问串行化
  • 使用不可变量,即:消除可变的
  • 使用线程封闭,即:消除共享的

加锁

即使用synchronized关键字

synchronized = 锁 + 代码块

锁,

  • 一般使用对象(Object)的内置锁,或者显示地使用Lock对象
  • 每一个Java对象都有且只有一个内置锁
  • 进入synchronized标识的代码块后,自动获取锁,退出代码块,释放锁
  • 在此期间,所有须要同一个锁的同步代码均阻塞
  • ps: 在Java中,锁的持有粒度是线程,而非调用

代码块

  • 可以是一个method,也可以是任意一段代码
  • 如果是method的话,对应的锁对象,其实就是this
  • 如果是一段代码,一般加锁,也加在this上面

只要搞清楚了锁是加在哪个对象上,程序中的哪些代码是互斥的,也就基本清楚了

同步(synchronized)既保证了操作的原子性,又保证了可见性

与此相对,volatile只能保证可见性,不能保证原子性,可以认为是一种轻量级的、使用限制较多的同步机制

使用不可变量

// TODO

使用线程封闭

如果程序运转所需的数据是线程封闭的,即:这份数据只能在同一个线程中访问,自然也就不会出现多线程的安全性问题了

典型的线程封闭就是使用ThreadLocal,按照JDK的说法,

ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

特别适合存放用户ID,事务ID,等线程相关的信息。例如,Spring的SecurityContextHolder就使用了ThreadLocal

The most fundamental object is SecurityContextHolder. This is where we store details of the present security context of the application, which includes details of the principal currently using the application. By default the SecurityContextHolder uses a ThreadLocal to store these details

发表评论

电子邮件地址不会被公开。 必填项已用*标注