synchronized
锁状态:根据对象头中的markword来进行标记,
状态:无锁,偏向锁,轻量级,重量级
同步原理:同步方法->使用方法常量池中的标志位ACC_SYNCHRONIZED
同步代码块->使用monitor_enter moniter_exit两个指令来完成,(编译器会保证即使在执行异常的情况下这两个指令也会成堆出现,从而避免了锁无法释放的场景)
jvm 源码
void ATTR ObjectMonitor::enter(TRAPS) {
// The following code is ordered to check the most common cases first
// and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
//记录当前请求锁的线程指针
Thread * const Self = THREAD ;
void * cur ;
*** 尝试获取监视器对象的锁,这行代码即是尝试将监视器的_owner指针指向当前线程 cur 应该是当前_owner的值
cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ; ***
//表明申请锁失败
if (cur == NULL) {
// Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
assert (_recursions == 0 , "invariant") ;
assert (_owner == Self, "invariant") ;
// CONSIDER: set or assert OwnerIsThread == 1
return ;
}
//申请成功
if (cur == Self) {
// TODO-FIXME: check for integer overflow! BUGID 6557169.
_recursions ++ ;
return ;
}
//当前线程是锁的持有者
if (Self->is_lock_owned ((address)cur)) {
assert (_recursions == 0, "internal state error");
_recursions = 1 ;
// Commute owner from a thread-specific on-stack BasicLockObject address to
// a full-fledged "Thread *".
_owner = Self ;
OwnerIsThread = 1 ;
return ;
}
// We've encountered genuine contention.
assert (Self->_Stalled == 0, "invariant") ;
Self->_Stalled = intptr_t(this) ;
// Try one round of spinning *before* enqueueing Self
// and before going through the awkward and expensive state
// transitions. The following spin is strictly optional ...
// Note that if we acquire the monitor from an initial spin
// we forgo posting JVMTI events and firing DTRACE probes.
if (Knob_SpinEarly && TrySpin (Self) > 0) {
assert (_owner == Self , "invariant") ;
assert (_recursions == 0 , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
Self->_Stalled = 0 ;
return ;
}
assert (_owner != Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (Self->is_Java_thread() , "invariant") ;
JavaThread * jt = (JavaThread *) Self ;
assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
assert (jt->thread_state() != _thread_blocked , "invariant") ;
assert (this->object() != NULL , "invariant") ;
assert (_count >= 0, "invariant") ;
// Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
Atomic::inc_ptr(&_count);
EventJavaMonitorEnter event;
{ // Change java thread status to indicate blocked on monitor enter.
JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_enter()) {
JvmtiExport::post_monitor_contended_enter(jt, this);
}
OSThreadContendState osts(Self->osthread());
ThreadBlockInVM tbivm(jt);
Self->set_current_pending_monitor(this);
// TODO-FIXME: change the following for(;;) loop to straight-line code.
for (;;) {
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition()
// or java_suspend_self()
EnterI (THREAD) ;
if (!ExitSuspendEquivalent(jt)) break ;
//
// We have acquired the contended monitor, but while we were
// waiting another thread suspended us. We don't want to enter
// the monitor while suspended because that would surprise the
// thread that suspended us.
//
_recursions = 0 ;
_succ = NULL ;
exit (false, Self) ;
jt->java_suspend_self();
}
Self->set_current_pending_monitor(NULL);
}
Atomic::dec_ptr(&_count);
assert (_count >= 0, "invariant") ;
Self->_Stalled = 0 ;
// Must either set _recursions = 0 or ASSERT _recursions == 0.
assert (_recursions == 0 , "invariant") ;
assert (_owner == Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
// The thread -- now the owner -- is back in vm mode.
// Report the glorious news via TI,DTrace and jvmstat.
// The probe effect is non-trivial. All the reportage occurs
// while we hold the monitor, increasing the length of the critical
// section. Amdahl's parallel speedup law comes vividly into play.
//
// Another option might be to aggregate the events (thread local or
// per-monitor aggregation) and defer reporting until a more opportune
// time -- such as next time some thread encounters contention but has
// yet to acquire the lock. While spinning that thread could
// spinning we could increment JVMStat counters, etc.
DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_entered()) {
JvmtiExport::post_monitor_contended_entered(jt, this);
}
if (event.should_commit()) {
event.set_klass(((oop)this->object())->klass());
event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid);
event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr()));
event.commit();
}
if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
}
}
上述获取监视器锁对象的代码是这样的:
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
//这个是判断当前处理器是不是多核处理器
int mp = os::is_MP();
//传入的参数为 当前线程ref 监视器_owner_ref NULL
//下述就是汇编代码了
__asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
: "=a" (exchange_value)
: "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
: "cc", "memory");
return exchange_value;
}
ReentrantLock
基于API层面实现,相比较synchronized(虚拟机层面)提供了公平锁,绑定多个条件,响应中断三大高级特性
package threadsafe.concurrentTest;
import java.sql.Time;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 测试可重入锁的高级特性 公平锁 绑定多个条件 响应中断
*/
public class ReentrantLockDemo {
Thread thread1 = null;
Thread thread2 = null;
private volatile int time = 1;
public static void main(String[] args) {
ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
// reentrantLockDemo.testFair();
// reentrantLockDemo.testUnFair();
// reentrantLockDemo.testInterrupt();
// reentrantLockDemo.thread1.interrupt();
reentrantLockDemo.testCondition();
}
public void testFair() {
ReentrantLock reentrantLock = new ReentrantLock(true);
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName() + "获取了锁");
} catch (Exception e) {
} finally {
System.out.println(Thread.currentThread().getName() + "释放了锁");
reentrantLock.unlock();
}
}, "Thread" + i).start();
}
}
public void testUnFair() {
ReentrantLock reentrantLock = new ReentrantLock();
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
reentrantLock.lock();
System.out.println(Thread.currentThread().getName() + "获取了锁");
} catch (Exception e) {
} finally {
System.out.println(Thread.currentThread().getName() + "释放了锁");
reentrantLock.unlock();
}
}, "Thread" + i).start();
}
}
public void testInterrupt() {
ReentrantLock reentrantLock = new ReentrantLock();
ReentrantLock reentrantLock1 = new ReentrantLock();
thread1 = new Thread(() -> {
try {
reentrantLock.lockInterruptibly();
TimeUnit.SECONDS.sleep(3);
reentrantLock1.lockInterruptibly();
} catch (Exception e) {
} finally {
System.out.println(Thread.currentThread().getName() + "结束");
reentrantLock.unlock();
reentrantLock1.unlock();
}
}, "Thread1");
thread1.start();
thread2 = new Thread(() -> {
try {
reentrantLock1.lockInterruptibly();
TimeUnit.SECONDS.sleep(3);
reentrantLock.lockInterruptibly();
} catch (Exception e) {
} finally {
System.out.println(Thread.currentThread().getName() + "结束");
reentrantLock1.unlock();
reentrantLock.unlock();
}
}, "Thread2");
thread2.start();
}
//线程1先打印5个A 线程2打印3个B 线程3打印2个C
public void testCondition() {
ReentrantLock reentrantLock = new ReentrantLock();
Condition condition1 = reentrantLock.newCondition();
Condition condition2 = reentrantLock.newCondition();
Condition condition3 = reentrantLock.newCondition();
new Thread(() -> {
try {
while (time != 1) {
condition1.await();
}
reentrantLock.lock();
for (int i = 0; i < 5; i++) {
System.out.println("A");
}
time = 2;
condition2.notify();
} catch (Exception e) {
} finally {
reentrantLock.unlock();
System.out.println("线程1释放了锁");
}
}, "Thread1").start();
new Thread(() -> {
try {
while (time != 2) {
condition2.await();
}
reentrantLock.lock();
for (int i = 0; i < 3; i++) {
System.out.println("B");
}
time = 3;
condition3.notify();
} catch (Exception e) {
} finally {
reentrantLock.unlock();
System.out.println("线程2释放了锁");
}
}, "Thread2").start();
new Thread(() -> {
try {
while (time != 3) {
condition3.await();
}
reentrantLock.lock();
for (int i = 0; i < 2; i++) {
System.out.println("C");
}
time = 1;
condition1.notify();
} catch (Exception e) {
} finally {
reentrantLock.unlock();
System.out.println("线程3释放了锁");
}
}, "Thread3").start();
}
}
探究ReentrantLock
所有ReentrantLock的操作都是通过Sync来进行完成的
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
源码描述:
Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
继承关系如下
Sync extends AbstractQueuedSynchronizer
AbstractQueuedSynchronized extends AbstractOwnableSynchronizer
AbstractQueuedSynchronized源码注释选段: Provides a framework for implementing blocking locks and related,
rely on a single atomic {@code int} value to represent state. 根据一个原子操作类型的int类型来表明当前状态
This class supports either or both a default <em>exclusive</em>
* mode and a <em>shared</em> mode 这个类支持独占和共享两种模式的选择
* Usually, implementation subclasses support only
* one of these modes, but both can come into play for example in a
* {@link ReadWriteLock} 通常情况下,其实现类只会选择一种模式实现,当然也有例外,比如读写锁
lock过程
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire(arg)->nonfairTryAcquire(acquires)
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//尚未加锁,直接加锁设置锁拥有者
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}//当前锁的请求者正好是锁的当前拥有者
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
Node.EXCLUSIVE=null
addWaiter(Node.EXCLUSIVE):
private Node addWaiter(Node mode) {
//将当前节点放置在队尾
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//第一次调用addWaiter的时候将会调用
enq(node);
return node;
}
enq(node):
//自旋式设置设置头尾
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
acquireQueued(addWaiter(Node mode), arg):
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//当前节点的前驱节点
final Node p = node.predecessor();
//当只有一个线程进入同步队列等待的时候,继续尝试一次获取锁的操作
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
//取消对锁的申请
if (failed)
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire(p, node):
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//前驱节点的状态
int ws = pred.waitStatus;
//如果前驱节点的状态已经设置为当前驱节点释放锁之后会唤醒后继节点
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
如果先驱节点已经取消了获取锁的行为,那么当前节点将持续向前寻找,直到找到等待状态满足条件的节点,而后跟在其后,由于这种方式也会导致这些放弃申请锁的节点被GC收集掉
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
//设置前驱节点新的waitStatus状态
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt():
private final boolean parkAndCheckInterrupt() {
//阻塞当前的线程,并且返回是否中止状态
LockSupport.park(this);
return Thread.interrupted();
}
//阻塞当前线程
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
}