jmm知识点

原子性:
对象类型:
对象地址读写,原子操作
并发读不可变状态,线程安全
并发读写可变状态,非线程线程
基本类型:
int,char数值读写,原子操作
long,double高低位,非原子操作
i++等组合操作,非原子操作

可见性:
final
初始化final字段确保可见性
volatile
读写volatile字段确保可见性
synchronized
同步块内读写字段确保可见性
happen before
遵守happen before次序可见性
lock
lock确保可见性,但重入的第二个锁应该不具有该特性
可排序:
Happen Before 法则
程序次序法则
如果A一定在B之前发生,则happen before,
监视器法则
对一个监视器的解锁一定发生在后续对同一监视器加锁之前
Volatie变量法则
写volatile变量一定发生在后续对它的读之前
线程启动法则
Thread.start一定发生在线程中的动作之前
线程终结法则
线程中的任何动作一定发生在括号中的动作之前(其他线程检测到这个线程已经终止,从Thread.join调用成功返回,Thread.isAlive()返回false)
中断法则
一个线程调用另一个线程的interrupt一定发生在另一线程发现中断之前。
终结法则
一个对象的构造函数结束一定发生在对象的finalizer之前
传递性
A发生在B之前,B发生在C之前,A一定发生在C之前。

@NotThreadSafe
public class UnsafeSequence {
private int value;

/* Returns a unique value. /
public int getNext() {
return value++;
}
}

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

//高并发跳过验证
if (condition) {
then ….
}

=================
public class NoVisibility {
private static boolean ready;
private static int number;

private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}

重排序

保证可见性
禁止重排序
不能保证原子性

class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}

volatile实现
内存屏障
基于保守策略的JMM内存屏障插入策略:

在每个volatile写操作的前面插入一个StoreStore屏障。
在每个volatile写操作的后面插入一个StoreLoad屏障。
在每个volatile读操作的后面插入一个LoadLoad屏障。
在每个volatile读操作的后面插入一个LoadStore屏障。

final
. Assuming the object is constructed “correctly”, once an object is constructed, the values assigned to the final fields in the constructor will be visible to all other threads without synchronization. In addition, the visible values for any other object or array referenced by those final fields will be at least as up-to-date as the final fields.

What does it mean for an object to be properly constructed? It simply means that no reference to the object being constructed is allowed to “escape” during construction

public FinalFieldExample() { // bad!
x = 3;
y = 4;
// bad construction - allowing this to escape
global.obj = this;
}

class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}

static void writer() {
f = new FinalFieldExample();
}

static void reader() {
if (f != null) {
int i = f.x;
int j = f.y;
}
}
}

Initialization safety guarantees that for properly constructed objects, all threads will see the correct values of final fields that were set by the constructor, regardless of how the object is published. Further, any variables that can be reached through a final field of a properly constructed object (such as the elements of a final array or the contents of a HashMap referenced by a final field) are also guaranteed to be visible to other threads.

For objects with final fields, initialization safety prohibits reordering any part of construction with the initial load of a reference to that object. All writes to final fields made by the constructor, as well as to any variables reachable through those fields, become “frozen” when the constructor completes, and any thread that obtains a reference to that object is guaranteed to see a value that is at least as up to date as the frozen value. Writes that initialize variables reachable through final fields are not reordered with operations following the post-construction freeze.

@Immutable
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;

public OneValueCache(BigInteger i,
BigInteger[] factors) {
lastNumber = i;
lastFactors = Arrays.copyOf(factors, factors.length);
}

public BigInteger[] getFactors(BigInteger i) {
if (lastNumber == null || !lastNumber.equals(i))
return null;
else
return Arrays.copyOf(lastFactors, lastFactors.length);
}
}
@ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache =
new OneValueCache(null, null);

public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i);
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors);
}
encodeIntoResponse(resp, factors);
}

安全发布
Safe publication makes all the values written before the publication visible to all readers that observed the published object

// Unsafe publication
public Holder holder;

public void initialize() {
holder = new Holder(42);
}

There are a few trivial ways to achieve safe publication:

Exchange the reference through a properly locked field (JLS 17.4.5)

Use static initializer to do the initializing stores (JLS 12.4)

Exchange the reference via a volatile field (JLS 17.4.5), or as the consequence of this rule, via the AtomicX classes

Initialize the value into a final field (JLS 17.5).

====+++++

public class SynchronizedCLFactory { //效率差
private Singleton instance;

public Singleton get() {
synchronized (this) {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
}

public class UnsafeDCLFactory { //线程不安全
private Singleton instance;

public Singleton get() {
if (instance == null) { // read 1, check 1
synchronized (this) {
if (instance == null) { // read 2, check 2
instance = new Singleton();
}
}
}
return instance; // read 3
}
}

In JMM-ese speak, there is no happens-before between the initializing stores in Singleton constructor, and the reads of Singleton fields.

One of the intents of the Java Memory Model is to allow reorderings for ordinary reads, otherwise the performance costs would be prohibitive. Specification-wise, as mentioned in happens-before consistency rules, a read action can observe the unordered write via the race. This is decided for each read action, regardless what other actions have already read the same location. In our example, that means that even though “read 1” could read non-null instance, the code then moves on to returning it, then it does another racy read, and it can read a null instance, which would be returned!

静态初始化
public class HolderFactory {
public static Singleton get() {
return Holder.instance;
}

private static class Holder {
public static final Singleton instance = new Singleton();
}
}

public class SafeDCLFactory {
private volatile Singleton instance;

public Singleton get() {
if (instance == null) { // check 1
synchronized(this) {
if (instance == null) { // check 2
instance = new Singleton();
}
}
}
return instance;
}
}

a single non-synchronized read of wrapper
public class FinalWrapperFactory {
private FinalWrapper wrapper;

public Singleton get() {
FinalWrapper w = wrapper;
if (w == null) { // check 1
synchronized(this) {
w = wrapper;
if (w == null) { // check2
w = new FinalWrapper(new Singleton());
wrapper = w;
}
}
}
return w.instance;
}

private static class FinalWrapper {
public final Singleton instance;
public FinalWrapper(Singleton instance) {
this.instance = instance;
}
}
}

there still no happens-before between publishing the Singleton instance, and reading of any of its fields.
public class UnsafeLocalDCLFactory implements Factory {
private Singleton instance; // deliberately non-volatile

@Override
public Singleton getInstance() {
Singleton res = instance;
if (res == null) {
synchronized (this) {
res = instance;
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}

a performance optimization for SafeDCLFactory
public class SafeLocalDCLFactory implements Factory {
private volatile Singleton instance;

@Override
public Singleton getInstance() {
Singleton res = instance;
if (res == null) {
synchronized (this) {
res = instance;
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}

Map cache = new HashMap();
synchronized(cache) { // wait
value = cache.get(key);
if (value == null) { value = load(key); // slow
cache.put(key, value);
}
}

ConcurrentMap cache = new ConcurrentHashMap();
value = cache.get(key);
if (value == null) { value = load(key); // repeat
cache.putIfAbsent(key, value);
}

Map cache = new HashMap();
value = cache.get(key); //cpu 100%
if (value == null) {
synchronized(cache) {
value = cache.get(key);
if (value == null) { value = load(key);
cache.put(key, value);
}
}
}
Map cache = new ConcurrentHashMap();
value = cache.get(key);
if (value == null) {
synchronized(cache) {
value = cache.get(key);
if (value == null) { value = load(key);
cache.put(key, value);
}
}
}

static class Node

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值