java.util.concurrent

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.

JavaConcurrencyInPractice对线程安全的准确定义:判断一个类是否是线程安全的,就看在多线程环境中,不管这个类在被多线程访问还是由JRE的按调度方式执行或交叉执行,都不需要额外加同步策略或在调用方法上做任何额外的补助工作的情况下是否还能得到正确的结果。

Race-condition
The most common type of race condition is check-then-act, where a potentially stale observation is used to make a decision on what to do next.
Atomicity(原子性,不可拆分)
While the increment operation,
++count,这是个复合操作,典型的读-改-写复合操作。 may look like a single action because of its compact syntax, it is not atomic, which means that it does not
execute as a single, indivisible operation. Instead, it is shorthand for a sequence of three discrete operations: fetch the
current value, add one to it, and write the new value back. This is an example of a read-modify-write operation, in which
the resulting state is derived from the previous state.


Intrinsic Locks自生锁synchronized

Every Java object can implicitly act as a lock for purposes of synchronization; these built-in locks are called intrinsic locks
or monitor locks. The lock is automatically acquired by the executing thread before entering a synchronized block and
automatically released when control exits the synchronized block, whether by the normal control path or by throwing
an exception out of the block. The only way to acquire an intrinsic lock is to enter a synchronized block or method
guarded by that lock.当执行到synchronized代码块里,自动获得锁,不管什么原因到synchronized块外的时候自动释放锁。
Intrinsic locks in Java act as mutexes互斥锁 (or mutual exclusion locks), which means that at most one thread may own the
lock. 只有一个线程可获得锁When thread A attempts to acquire a lock held by thread B, A must wait, or block, until B releases it. If B never
releases the lock, A waits forever.

Reentrancy
because intrinsic locks are reentrant, if a thread tries to acquire a lock that it already holds, the request succeeds. Reentrancy
means that locks are acquired on a per-thread rather than per-invocation basis.


Reentrancy is implemented by
associating with each lock an acquisition count and an owning thread. When the count is zero, the lock is considered
unheld. 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
试想给线程加个'获得次数count'的属性,当同一个线程再次获得该锁,count+1;当线程释放锁的时候,count-1;所以当count==0的时候,锁才算是释放了。

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. In this case, we say that the variable is guarded by that lock
实例的所有可变属性都应该用'同一个锁'管控。
Every shared, mutable variable should be guarded by exactly one lock. Make it clear to maintainers which lock that is.

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.

Avoid holding locks during lengthy computations or operations at risk of not completing quickly such as network or
console I/O

避免在network和IO这样的耗时操作中加锁--降低性能
In the absence of synchronization, the compiler, processor, and runtime can do some downright weird things to the
order in which operations appear to execute. Attempts to reason about the order in which memory actions "must"
happen in insufficiently synchronized multithreaded programs will almost certainly be incorrect

synchronized 不充分也会导致错误。
Stale Data

Reading data without synchronization is analogous to using the READ_UNCOMMITTED isolation level in a database, where you are willing to
trade accuracy for performance.


Sharing Objects
The Java Memory Model requires fetch and store operations to be atomic,
but for nonvolatile long and double variables, the JVM is permitted to treat a 64-bit read or write as two separate 32-bit operations. If the reads and writes occur in different threads, it is therefore possible to read a nonvolatile long and
get back the high 32 bits of one value and the low 32 bits of another.
没有加volatile修饰的long和double变量,JVM会把64-bit的读或写操作拆成2次32-bit读或写操作。所以在多线程环境中可能读到错误的随机数。
Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-
to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock

Volatile Variables
When a field is declared volatile, the compiler and
runtime are put on notice that this variable is shared and that operations on it should not be reordered with other
memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other
processors, so a read of a volatile variable always returns the most recent write by any thread.

volatile修饰可以保证该变量的操作不会被jvm reorder,保证读到值总是最新写入的。
Use volatile variables only when they simplify implementing and verifying your synchronization policy; avoid using
volatile variables when verifying correctness would require subtle reasoning about visibility. Good uses of volatile
variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an
important lifecycle event (such as initialization or shutdown) has occurred.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值