首页 > 代码库 > 读书笔记-----Java并发编程实战(一)线程安全性

读书笔记-----Java并发编程实战(一)线程安全性

线程安全类:在线程安全类中封装了必要的同步机制,客户端无须进一步采取同步措施

示例:一个无状态的Servlet

1 @ThreadSafe2 public class StatelessFactorizer implements Servlet{3         public void service(ServletRequest req,ServletResponse resp){4             BigInteger i = extractFromRequest(req);5             BigInteger[] factors = factor(i);6             encodeIntoResponse(resp,factors);7         }8 }

这个类是无状态的,因为它既不包含任何域,也不包含任何对其他类中域的引用,计算过程中用到的变量是局部变量没有被共享。

无状态对象一定是线程安全的。

 

在并发编程中,由于不恰当执行时序而出现不正确结果的情况,称为竞态条件。

最常见的竞态类型就是先检查后执行操作:比如单例中的延迟初始化。

像递增,递减操作看上去只有一个操作,但这个操作并非原子的,会导致结果变得不可靠。这种情况称为:读取-修改-写入的复合操作,也是竞态类型的一种。

对于这些竞态条件类型的操作可以加上同步锁,或者使用一个现有的线程安全类。

如:

 1  @ThreadSafe 2  public class CountingFactorizer implements Servlet{ 3          private final AtomicLong count = new AtomicLong(0); 4          public long getCount(){return count.get();} 5          public void service(ServletRequest req,ServletResponse resp){ 6              BigInteger i = extractFromRequest(req); 7              BigInteger[] factors = factor(i); 8              count.incrementAndGet(); 9              encodeIntoResponse(resp,factors);10          }11  }

在java.util.concurrent.atomic包中包含了一些原子变量类,用于实现在数值和对象引用上的原子状态转换。

注意:当在不变性条件中涉及多个变量时,各个变量间并不是彼此独立的,而是某个变量的值会对其他变量的值产生约束。因此,当更新某一个变量时,需要在同一个原

子操作中对其他变量同时更新

 

重入:当某个线程请求一个由其他线程持有的锁时,发出的请求线程会被阻塞。然而内置锁是可以重入的,因此某个线程试图获得一个已经由他自己持有的锁,那么这个请求就会成

功。

这个过程可以描述为:线程请求一个未被持有的锁,JVM记下这个新的锁持有者,计数值置为1,当这个线程再次获取这个锁,计数值将递增。当线程退出同步代码块时,计数器会相

应的递减。当计数值为0时,这个锁将被释放。

示例:

 1 public class Widget{ 2      public synchronized void doSomething(){ 3              ... 4       } 5 } 6  7 public class LoggingWidget extends Widget{ 8       public synchronized void doSomething(){ 9                  super.doSomething();10       }11 }

使用锁保护时,对于包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。

注意:当执行时间较长的计算或者无法快速完成的操作时,一定不要持有锁。