Open afredlyj opened 8 years ago
在Java中,线程可以分为如下几种状态:NEW, RUNNABLE, BLOCKED, WAITING, TIME_WAITING, TERMINATED.
start
方法时,线程处于NEW
状态。start
之后处于的状态,但是该状态并不能表明线程正在运行,也可能在等待cpu调度。BLOCKED
状态,另外,如果线程调用监视器对象的wait
方法时,会释放锁,当另外线程调用notify
或notifyAll
时,调用wait
的线程会再次尝试获取监视器锁,此时该线程也处于BLOCKED
状态。wait
方法之后,处于该状态,另外,调用Thread#join
或LockSupport#park
方法也会导致线程进入该状态。TIME_WAITING
当线程调用如下几种方法,都导致线程处于TIME_WAITING
状态。
Thread.sleep Object#wait(long) Object.wait} with timeout join(long) Thread.join with timeout LockSupport#parkNanos LockSupport.parkNanos LockSupport#parkUntil LockSupport.parkUntil
join
方法,该方法使得调用线程进入WAITING
状态。当HashMap用在并发环境下时,有一定几率导致死循环,从而导致CPU 100%。详细分析可以参考这里,大致就是多个线程同时resize
,形成环形链表,如果此时有get
操作,并hash到这个环形链表,就会进入死循环。
说到底,这是错误使用JDK导致的,因为HashMap并不能用于多线程环境。
产生死锁的四个必要条件:
use volatile fields when said field is ONLY UPDATED by its owner thread and the value is only read by other threads, you can think of it as a publish/subscribe scenario where there are many observers but only one publisher. However if those observers must perform some logic based on the value of the field and then push back a new value then I go with Atomic* vars or locks or synchronized blocks, whatever suits me best. In many concurrent scenarios it boils down to get the value, compare it with another one and update if necessary, hence the compareAndSet and getAndSet methods present in the Atomic* classes.
Check the JavaDocs of the java.util.concurrent.atomic package for a list of Atomic classes and an excellent explanation of how they work (just learned that they are lock-free, so they have an advantage over locks or synchronized blocks)
出处:Volatile boolean vs AtomicBoolean
但是不知道为啥题主选择的另外一个答案=_=...
该类用于原子性修改对象的int成员变量,AtomicLongFieldUpdater
也是类似。该类是抽象类,使用时通过newUpdater
返回一个内部实现类AtomicIntegerFieldUpdaterImpl
,在初始化时,会使用反射确认调用类的访问权限,确定访问权限之后,继续判断类型是否是int.class
,是否有volatile
标识,最后获取目标域的偏移量,为后面的CAS操作做准备。
AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName, Class<?> caller) {
Field field = null;
int modifiers = 0;
try {
field = tclass.getDeclaredField(fieldName);
modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers);
sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
Class fieldt = field.getType();
if (fieldt != int.class)
throw new IllegalArgumentException("Must be integer type");
if (!Modifier.isVolatile(modifiers))
throw new IllegalArgumentException("Must be volatile type");
this.cclass = (Modifier.isProtected(modifiers) &&
caller != tclass) ? caller : null;
this.tclass = tclass;
offset = unsafe.objectFieldOffset(field);
}
java doc的说明比较明了:
/**
* A reflection-based utility that enables atomic updates to
* designated {@code volatile} reference fields of designated
* classes. This class is designed for use in atomic data structures
* in which several reference fields of the same node are
* independently subject to atomic updates. For example, a tree node
* might be declared as
*
* <pre> {@code
* class Node {
* private volatile Node left, right;
*
* private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
* AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
* private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
* AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
*
* Node getLeft() { return left; }
* boolean compareAndSetLeft(Node expect, Node update) {
* return leftUpdater.compareAndSet(this, expect, update);
* }
* // ... and so on
* }}</pre>
*
* <p>Note that the guarantees of the {@code compareAndSet}
* method in this class are weaker than in other atomic classes.
* Because this class cannot ensure that all uses of the field
* are appropriate for purposes of atomic access, it can
* guarantee atomicity only with respect to other invocations of
* {@code compareAndSet} and {@code set} on the same updater.
AtomicIntegerFieldUpdater的使用场景是当一个原子性的类,有多个相互独立的成员变量需要变更时。
另外,AtomicIntegerFieldUpdater只能保证当前updater范围内的原子性,当多个updater实例操作同一个对象时并不能保证(这是显然的,自己管自己能力范围之内的事儿)。而AtomicReference
将对象作为自己的成员变量value
,更容易控制。
AtomicXXX
原子操作类相比于volatile
,个人理解多了一个compareAndSet
操作。
When to use AtomicReference in Java? AtomicReferenceFieldUpdater - methods set, get, compareAndSet semantics
JAVA并发编程实践读书笔记
线程安全
out-of-thin-air safety。当一个线程在没有同步的情况下读取变量,它可能会得到一个过期值,但是至少它可以看到某个线程设置的一个真实值,而不是凭空而来的值。除了没有声明为volatile的64位double和long,最低限的安全性应用于所有的变量。
并不推荐过度依赖volatile变量所提供的可见性,只有满足下面所有的标准后,才能使用volatile变量:
发布和逸出
发布(publishing)一个对象的意思是,使它能够被当前范围之外的代码所使用。
一个对象在尚未准备好时就将它发布,这种情况称作逸出(escape)。 创建之后状态不能被修改的对象叫做不可变对象,不可变对象是线程安全的,只有满足如下状态,一个对象才是不可变的:
在不可变对象的内部,同样可以使用可变性对象来管理它们的状态。
synchronized说明
synchronized提供了以下功能:
我们将synchronized使用的基本规则总结为下面3条:
在Java代码中,不能有synchronized 修饰的变量,否则会编译错误,但是可以有volatile修饰的变量。
线程等待和唤醒
只有获取到对象的监视器后,才能调用wait和notify方法。
在窃取工作的设计中,每个消费者都有自己的双端队列,如果一个消费者完成了自己双端队列中的全部工作,它可以偷取其他消费者双端队列末尾的工作。因为工作线程并不会竞争一个共享队列,所以效率比生产者消费者模式要高。
Synchronizer
Synhronizer是一个对象,根据本身的状态调节线程的控制流,阻塞队列可以扮演一个Synchronizer的角色,其他类型的Synchronizer的角色包括信号量(semaphore)、关卡(barrier)以及闭锁(latch)。
所有的Synchronizer都享有类似的结构特性:它们封装状态,而这些状态决定着线程执行到在某一点时是通过还是被迫等待;它们提供操控状态的方法,以及高效地等待Synchronizer进入到期望状态的方法。
闭锁可以延迟线程的进入知道线程到达终止状态。可以用来确保特定活动知道其他的活动完成后才发生。CountDownLatch是一个闭锁实现。FutureTask也可以作为闭锁。
FutureTask等价于一个可携带结果的Runnable,并且有3个状态:等待、运行和完成。其中,完成包括所有计算以任意的方式结束,包括正常结束、取消和异常。一旦FutureTask进入完成状态,它会永远停止在这个状态上。
计数信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数量,计数信号量可以用来实现资源池或者给一个容器限定边界。
总结
happens-before 规则描述的是变量之间的可见性。
volatile 和重排序(深入理解java内存模型)
重排序分为编译器重排序和处理器重排序,为了实现volatile内存语义,JMM会分别限制这两种类型的重排序。
final
对于final域,编译器和处理器要遵守两个重排序规则:
中断