Writing thread-safe code is managing access to state and in particular to shared, mutable state.

Object's state is its data, stored in state variables such as instance or static fields.

Whether an object needs to be thread-safe depends on whether it will be accessed from multiple threads.

Synchronization includes

  1. Synchronized keyword
  2. Volatile variables
  3. Explicit locks
  4. Atomic variables

Ways to avoid inappropriate synchronization with multiple threads access.

  1. Don't share the state variable across threads;
  2. Make the state variable immutable; or
  3. Use synchronization whenever accessing the state variable.  

Good practice on designing thread-safe classes

  1. Good object-oriented techniques - encapsulation(Don't expose the accessibility of the fields of the class too much).
  2. Immutability
  3. Clear specification of invariants  

2.1 What is Thread Safety

A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.

Thread safe classes encapsulate any needed synchronization so that clients need not provide their own.

Stateless objects are always thread-safe.

eg. It is only when servlets want to remember things from one request to another that the thread safety requirement becomes an issue.

2.2 Atomicity

Classic operation scenario

  1. read-modify-write: To increment a counter, you have to know its previous value and make sure no one else changes or uses that value while you are in mid‐update.
  2. check‐then‐act: you observe something to be true and then take action based on that observation (create X); but in fact the observation could have become invalid between the time you observed it and the time you acted on it (someone else created X in the meantime), causing a problem (unexpected exception, overwritten data, file corruption).

2.2.1 Race Conditions

A race condition occurs when the correctness of a computation depends on the relative timing or interleaving of multiple threads by the runtime.

@NotThreadSafe

public class LazyInitRace {

    private ExpensiveObject instance = null;   

    public ExpensiveObject getInstance() {
if (instance == null)
instance = new ExpensiveObject();
return instance;
}
}  

Operations A and B are atomic with respect to each other, from the perspective of a thread executing A, when another thread executes B, either all of B has executed or none of it has. An atomic operation is one that is atomic with respect to all operations, including itself, that operate on the same state.

@NotThreadSafe

public class UnsafeCountingFactorizer implements Servlet {

    private long count = 0;   

    public long getCount() {
return count;
} public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = factor(i);
++count;
encodeIntoResponse(resp, factors);
}
}    

The java.util.concurrent.atomic package contains atomic variable classes for effecting atomic state transitions on

numbers and object references. By replacing the long counter with an AtomicLong, we ensure that all actions that

access the counter state are atomic.

@ThreadSafe

public class CountingFactorizer implements Servlet {

    private final AtomicLong count = new AtomicLong(0);   

    public long getCount() {
return count.get();
} public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = factor(i);
count.incrementAndGet();
encodeIntoResponse(resp, factors);
}
}

Principle

Where practical, use existing thread-safe objects, like AtomicLong, to manage your class's state. It is simpler to reason about the possible states and state transitions for existing thread-safe objects than it is for arbitrary state variables, and this makes it easier to maintain and verify thread safety.

2.3 Locking

Dealing with more than one states currency operations within one object.

Principle

To preserve state consistency, update related state variables in a single atomic operation.

2.3.1 Intrinsic Locks

A synchronized block has two parts: a reference to an object that will serve as the lock, and a block of code to be guarded by that lock. A synchronized method is shorthand for a synchronized block that spans an entire method body, and whose lock is the object on which the method is being invoked. (Static synchronized methods use the Class object for the lock.)

2.3.2 Reentrancy

Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

When a thread acquires a previously unheld lock, the JVM records the owner and sets the acquisition count to one. If that same thread acquires the lock again, the count is incremented, and when the owning thread exits the synchronized block, the count is decremented. When the count reaches zero, the lock is released.

2.4 Guarding State with Locks

For each mutable state variable that may be accessed by more than one thread, all accesses to that variable must be performed with the same lock held.

For every invariant that involves more than one variable, all the variables involved in that invariant must be guarded by the same lock.

put-if-absent operation

if (!vector.contains(element))
vector.add(element);

2.5 Liveness and Performance

Refined solution for concurrent operation on more than on state object inside the Class instance

@ThreadSafe

public class CachedFactorizer implements Servlet {

    @GuardedBy("this")
private BigInteger lastNumber; @GuardedBy("this")
private BigInteger[] lastFactors; @GuardedBy("this")
private long hits; @GuardedBy("this")
private long cacheHits; public synchronized long getHits() {
return hits;
} public synchronized double getCacheHitRatio() {
return (double) cacheHits / (double) hits;
} public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = null;
synchronized (this) {
++hits;
if (i.equals(lastNumber)) {
++cacheHits;
factors = lastFactors.clone();
}
} if (factors == null) {
factors = factor(i);
synchronized (this) {
lastNumber = i;
lastFactors = factors.clone();
}
}
encodeIntoResponse(resp, factors);
}
}  

Principle

  1. There is frequently a tension between simplicity and performance. When implementing a synchronization policy, resist the temptation to prematurely sacrifice simplicity (potentially compromising safety) for the sake of performance.
  2. Avoid holding locks during lengthy computations or operations at risk of not completing quickly such as network or console I/O.

Java Concurrency In Practice -Chapter 2 Thread Safety的更多相关文章

  1. Java Concurrency In Practice - Chapter 1 Introduction

    1.1. A (Very) Brief History of Concurrency motivating factors for multiple programs to execute simul ...

  2. Java Concurrency in Practice 读书笔记 第十章

    粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...

  3. Java Concurrency in Practice——读书笔记

    Thread Safety线程安全 线程安全编码的核心,就是管理对状态(state)的访问,尤其是对(共享shared.可变mutable)状态的访问. shared:指可以被多个线程访问的变量 mu ...

  4. Java Concurrency In Practice

    线程安全 定义 A class is thread-safe if it behaves correctly when accessed from multiple threads, regardle ...

  5. 读Java Concurrency in Practice. 第六章.

    这一章开讲任务执行.绝大多数并发程序的工作都可以分解为抽象的.互不相关的工作单元,称之为任务(Task). 使用java线程来执行任务 以web服务器的实现举例, 此时将用户的一次连接,当做一个独立的 ...

  6. java并发编程实战(java concurrency in practice)

    第一章   线程共享进程范围内的资源,但每个线程都有各自的程序计数器.栈以及局部变量等. 多个线程可以同时调度到多个CPU上运行.   线程的优势? 在服务应用程序中,可以提升资源利用率以及系统吞吐率 ...

  7. java concurrency in practice读书笔记---ThreadLocal原理

    ThreadLocal这个类很强大,用处十分广泛,可以解决多线程之间共享变量问题,那么ThreadLocal的原理是什么样呢?源代码最能说明问题! public class ThreadLocal&l ...

  8. Java Concurrency in Practice 读书笔记 第二章

    第二章的思维导图(代码迟点补上):

  9. 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则

    转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到 ...

随机推荐

  1. Windows魔法堂:解决“由于启动计算机时出现页面文件配置问题.......”

    一.前言 昨晚终于在VirtualBox中安装好Win7了,但在系统启动后弹出窗报“由于启动计算机时出现页面文件配置问题.......”,于是度娘一下.以下记录以供日后查阅. 二.原因 网上说的是在使 ...

  2. Python3操作MySQL,查询数据并保存到文件中

    我们在测试过程中,可能需要到数据库中拉去一些数据,为从测试准备.比如最近在做接口性能测试的时候,就需要很多数据来支撑,所以就需要的数据库去查询数据,下面就是python3 查询 mysql 并且保存到 ...

  3. 查找最小的k 个元素之C#算法实现

    紧接着上一篇微软编程面试100题,这次想解决的是查找最小的K个元素,题目是:输入n 个整数,输出其中最小的k 个.例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 ...

  4. C#调用webservice 时如何传递实体对象

    在webservice端公开一个实体类,然后实例化,赋值,然后再给到webservice,可以实现,但是,即使调用端和service端的实体类完全一致,你也要重新实例化service端的,重新赋值,将 ...

  5. Tesseract-OCR引擎 入门

    OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程. Tesseract:开源的OCR识别引擎,初期Tesseract引 ...

  6. sql server聚合函数sum计算出来为空,怎样返回0

    通常我们计算数据库中表的数据有几个常用的聚合函数 1.count : 计数 2.sum: 计算总和 3.avg: 取平均值 4.max: 取最大值 5.min: 取最小值 6.isnull: 当返回数 ...

  7. C# 快速反射 IL

    public class FastInvoke { public delegate object FastInvokeHandler(object target, object[] paramters ...

  8. PostgreSQL avg()函数

    PostgreSQL的AVG函数是用来找出各种记录中的一个字段的平均值. 为了理解AVG函数考虑表COMPANY 有如下记录: testdb# select * from COMPANY; id | ...

  9. Html==>>一些经典

    1.CSS overflow 属性 2.<input>标签 <input> 标签用于搜集用户信息. 1 type属性 根据不同的 type 属性值,输入字段拥有很多种形式.可以 ...

  10. 环境搭建二 secureCRT配置

    上一篇里面讲到了虚拟机安装,以及secureCRT的远程连接.此篇文章介绍secureCRT的配置. 颜色设置 参考   http://jingyan.baidu.com/article/a681b0 ...