新版本的jdk 8的Concurrent Hash Map有两个新方法.
computeIfAbsent
computeIfPresent
putIfAbsent - 旧方法
我理解putIfAbsent和computeIfAbsent的用例.但我不确定何时使用computeIfPresent.另外,如果我现在有computeIfPresent,为什么还需要putIfAbsent. putIfAbsent会创建至少一个额外的值实例.
原因只是具有向后兼容性吗?
嗨,下面是Effective Java 2nd Edition的片段.在这里,作者声称下面的代码比你不使用结果变量快25%.根据书中的"这个变量的作用是确保该字段在已经初始化的常见情况下只读取一次." .我无法理解为什么这个代码在初始化之后会比较快,如果我们不使用Local变量结果.在任何一种情况下,无论是否使用局部变量结果,初始化后只有一个易失性读取.
// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud) 请参考以下代码.当我运行代码时,我能够更改最终的非静态变量的值.但是,如果我尝试更改最终静态变量的值,那么它会抛出java.lang.IllegalAccessException.
我的问题是为什么它不会在非静态最终变量的情况下抛出异常,反之亦然.为什么不同?
import java.lang.reflect.Field;
import java.util.Random;
public class FinalReflection {
final static int stmark = computeRandom();
final int inmark = computeRandom();
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
FinalReflection obj = new FinalReflection();
System.out.println(FinalReflection.stmark);
System.out.println(obj.inmark);
Field staticFinalField = FinalReflection.class.getDeclaredField("stmark");
Field instanceFinalField = FinalReflection.class.getDeclaredField("inmark");
staticFinalField.setAccessible(true);
instanceFinalField.setAccessible(true);
instanceFinalField.set(obj, 100);
System.out.println(obj.inmark);
staticFinalField.set(FinalReflection.class, 101);
System.out.println(FinalReflection.stmark);
}
private static int computeRandom() {
return new Random().nextInt(5);
}
}
Run Code Online (Sandbox Code Playgroud) 以上是ConcurrentLinkedQueue的源代码.我无法理解一个条件.
条件(p == q)将如何来自offer方法的以下代码段代码
public boolean offer(E e) {
checkNotNull(e);
final Node<E> newNode = new Node<E>(e);
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
// p is last node
if (p.casNext(null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
if (p != t) // hop two nodes at a …Run Code Online (Sandbox Code Playgroud) 下面的代码片段来自Effective Java 2nd Edition Double Checked Locking
//仔细检查实例字段的延迟初始化的惯用语
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null)// Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,双重检查锁定的主要问题是在第二次检查锁定内重新排序,以便另一个线程可能看到字段/结果的值设置为可能仍然在执行中.为避免这种情况,我们将字段的引用视为易失性,以保证可见性和重新排序.
但这也可以通过以下代码实现
private FieldType field; // non volatile
private volatile boolean fence = false;
FieldType getField() {
if (field == null) { // First check (no locking) // …Run Code Online (Sandbox Code Playgroud) 以下文字来自jls http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
Even then, there are a number of complications. If a final field is
initialized to a compile-time constant expression (§15.28) in the field
declaration, changes to the final field may not be observed, since uses of that
final field are replaced at compile time with the value of the constant
expression.
Run Code Online (Sandbox Code Playgroud)
任何人都可以给我更好的解释.我无法理解这一说法changes to the final field may not be observed.可以借助例子.
提前致谢
我正在阅读 Hans 的一篇文章,他认为在 lazySet 或最终变量 write 之前还需要 LoadStore 。
他展示了我无法理解的特定比赛条件。
http://www.hboehm.info/c++mm/no_write_fences.html 见 Recipient writes to object。
xa = 43 的线程 1 存储如何可以通过 StoreStore 屏障完成非常违反直觉,因为这样就完全违背了 StoreStore Barrier 的目的。
类似的论点在这里http://shipilev.net/blog/2014/all-fields-are-final/
在此处复制 Shiplev:
“JSR 133 Cookbook 只需要 StoreStore,但也可能需要 LoadStore 屏障。这涵盖了当最终字段从其他一些经历了激烈更新的字段初始化时的极端情况。这种极端 情况可以通过运行时优化来实现,它会发现不需要最终存储,将值放在局部变量中,因此打破了 StoreStore 单独的排序保证”
*运行时如何确定不需要最终存储,如果负载被传递/重新排序 StoreStore Barrier 然后存储到本地变量也会通过 storeStore 屏障传递/重新排序,这是我不太明白的部分,为什么存储到局部变量可以使用 StoreStore Barrier 重新排序。运行时如何/何时可以确定存储到局部变量就足够了 *
如果有人能通过一些简单的例子更详细地解释他们都提到的竞争条件是什么,那将是非常有帮助的。
我们知道,在声明为volatile之前,long和double赋值在Java中不是原子的.我的问题是它在我们的编程实践中是如何真正重要的.例如,如果您看到下面的类,其对象在多个线程之间共享.
/**
* The below class is not thread safe. the assignments to int values would be
* atomic but at the same time it not guaranteed that changes would be visible to
* other threads.
**/
public final class SharedInt {
private int value;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
Run Code Online (Sandbox Code Playgroud)
现在考虑另一个SharedLong
/**
* The below class is not thread safe because here the assignments to long
* are …Run Code Online (Sandbox Code Playgroud) 没有任何一个操作ArrayBlockingQueue与其他任何操作并发; 他们总是采取同样的锁.即使对于该size()方法,它也需要锁定.
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
Run Code Online (Sandbox Code Playgroud)
虽然执行LinkedBlockingQueue你有两个锁:put和take.并且因为size()它使用AtomicInteger所以不需要锁.
所以我的问题是:为什么这个实现在并发包中 - ArrayBlockingQueue真的是并发的?
java ×9
concurrency ×5
volatile ×4
final ×2
java-ee ×2
jls ×2
api ×1
atomic ×1
performance ×1
queue ×1
reflection ×1
static ×1