JAVA并发编程实战 ——线程安全性
2016-12-19 23:04
288 查看
以前也算是看过并发编程实战这本书。但是一直做的是书中的笔记。如今从头看此书。希望把笔记记录成博客。以便以后查询。
怎么确定一个类是线程安全的:
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要添加额外的同步或者协同。这个类都能表现出正确的行为,那么就称这个类是线程安全的。
2.2.1:无状态对象一定是线程安全的
在本书中描述是:既不包含任何域,也不包含任何对其它类中域的引用。
在没有同步的情况下统计已处理请求数量的Servlet(不要这么做)
UnsafeContingFactorizer是非线程安全的。当多个线程访问时候,count在进行++count时,就会产生:竞态条件。 ++count在JVM中他的执行过程是 读取-修改-写入。多个线程对count进行++操作时候,就可能会产生多个线程读取的是同一个值,修改后的值一直,导致统计不准确。
2.2.2
延迟初始化中的竟态条件:
最常见的就是我们在单例模式中,我们可以采取延迟初始化而避免线程不安全。当然下面代码是线程不安全的。是一个错误示例:
2.2.3 复合操作
包含一组必须以原子方式执行的操作我们称之为符合操作。如:延迟初始化、读取-修改-写入。
我们有时候可以采取原子变量类。java.util.concurrent.atomic中的原子变量类来保证线程安全性
这样就可以解决线程安全性问题。当然对于java.utilconcurrent包下面的类会在后续读到的时候进行想写的记录。也会对源码进行分析记录。
2.3 锁
2.3.1:Java提供了一种内置的锁机制来支持原子性——同步代码块(Synchronized Block).被Synchronized 修饰的普通方法的锁就是方法调用所在的对象。简单讲就是对象锁。静态的Synchronized方法是一Class对象作为锁。也就是类锁。Java的内置锁是一种互斥锁:也就是说最多只有一个线程能持有这种锁。
2.3.2:重入:java内置锁是可以重入的。如果某个线程试图获取自己已经拥有的锁,那么这个请求就会成功。 “重入” 意味着获取锁的操作粒度是线程,而不是调用。
怎么确定一个类是线程安全的:
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要添加额外的同步或者协同。这个类都能表现出正确的行为,那么就称这个类是线程安全的。
2.2.1:无状态对象一定是线程安全的
在本书中描述是:既不包含任何域,也不包含任何对其它类中域的引用。
在没有同步的情况下统计已处理请求数量的Servlet(不要这么做)
public class UnsafeCountingFactorizer implements Servlet { private long count = 0; public long getCount() { return count; } @Override public void service(ServletRequest request, ServletResponse response){ BigInteger i = extraactFromeRequest(request); BigInteger[] factors = factor(i); ++count; encodeIntoResponse(response, factors); } }
UnsafeContingFactorizer是非线程安全的。当多个线程访问时候,count在进行++count时,就会产生:竞态条件。 ++count在JVM中他的执行过程是 读取-修改-写入。多个线程对count进行++操作时候,就可能会产生多个线程读取的是同一个值,修改后的值一直,导致统计不准确。
2.2.2
延迟初始化中的竟态条件:
最常见的就是我们在单例模式中,我们可以采取延迟初始化而避免线程不安全。当然下面代码是线程不安全的。是一个错误示例:
//这个是线程不安全的。只是示例延迟初始化也会产生竟态条件 public class LazyInitRace { private LazyInitRace lazyInitRace ; private LazyInitRace(){}; public LazyInitRace getInstance() { if(lazyInitRace == null) { lazyInitRace = new LazyInitRace(); } return lazyInitRace; } }
2.2.3 复合操作
包含一组必须以原子方式执行的操作我们称之为符合操作。如:延迟初始化、读取-修改-写入。
我们有时候可以采取原子变量类。java.util.concurrent.atomic中的原子变量类来保证线程安全性
public class UnsafeCountingFactorizer implements Servlet { private final AtomicLong count = new AtomicLong(0); public long getCount() { return count.get(); } @Override public void service(ServletRequest request, ServletResponse response){ BigInteger i = extraactFromeRequest(request); BigInteger[] factors = factor(i); count.incrementAndGet(); encodeIntoResponse(response, factors); } }
这样就可以解决线程安全性问题。当然对于java.utilconcurrent包下面的类会在后续读到的时候进行想写的记录。也会对源码进行分析记录。
2.3 锁
2.3.1:Java提供了一种内置的锁机制来支持原子性——同步代码块(Synchronized Block).被Synchronized 修饰的普通方法的锁就是方法调用所在的对象。简单讲就是对象锁。静态的Synchronized方法是一Class对象作为锁。也就是类锁。Java的内置锁是一种互斥锁:也就是说最多只有一个线程能持有这种锁。
2.3.2:重入:java内置锁是可以重入的。如果某个线程试图获取自己已经拥有的锁,那么这个请求就会成功。 “重入” 意味着获取锁的操作粒度是线程,而不是调用。
//内置锁可重入,就不会让这样的代码发生死锁。 public class Widget { public synchronized void doSomething() { ........... } public class loggingWidget extends doSomething() { public synchronized void doSomething() { ........... super.doSomethin(); } } }
相关文章推荐
- JAVA并发编程实战 ——线程安全性
- JAVA并发编程实战 ——线程安全性
- JAVA并发编程实战 ——线程安全性
- Java并发编程实战(学习笔记 一 第二章 线程安全性)
- JAVA并发编程实战 ——线程安全性
- Java并发编程实战 - 第2章 线程安全性
- Java并发编程实战笔记(一):线程安全性
- JAVA并发编程实战 ——线程安全性
- 《Java并发编程实战》第二章 线程安全性 读书笔记
- 《Java并发编程实战》第二章 线程安全性 读书笔记
- JAVA并发编程实战---第二章:线程安全性
- JAVA并发编程实战 ——线程安全性
- 《Java并发编程实战》学习笔记之 第2章 线程安全性
- JAVA并发编程实战 读书笔记(一)线程安全性
- JAVA并发编程实战 ——线程安全性
- 《Java并发编程实战》---线程安全性---加锁
- 《Java并发编程实战》---线程安全性---线程封闭
- 《java并发编程实战》随笔——第二章 线程安全性
- java并发编程实战笔记-线程安全性
- 《java并发编程实战》读书笔记1--线程安全性,内置锁,重入,状态