Java中的并發編程,使用鎖是幾乎不可避免的。Java提供了很多鎖機制,其中一些被設計為在競爭不激烈的情況下實施輕量級鎖,其中比較有名的就是偏向鎖和自旋鎖。
偏向鎖是為了解決競爭激烈的場景下,鎖競爭會造成性能急劇下降和額外的開銷。在偏向鎖場景下,鎖的所有權并沒有傳遞給其他線程,而是只針對第一次申請的線程進行標記,并且僅當該線程釋放鎖后才被取消。這種處理有效地避免了競爭激烈的情況下頻繁的鎖升級。
public class BiasedLockingTest { static Point point = new Point(); static void test() { long startTime = System.currentTimeMillis(); for (int i = 0; i< 10000000; i++) { point.move(i, i); } long time = System.currentTimeMillis() - startTime; System.out.println("time:" + time); } public static void main(String[] args) { test(); } } class Point { int x, y; final boolean equals(Point other) { return x == other.x && y == other.y; } void move(int dx, int dy) { x += dx; y += dy; } }
自旋鎖,是一種比較簡單和高效的鎖機制。如果鎖在嘗試獲取過程中,沒有被其他的線程占據的話,那么鎖申請者將立刻得到鎖;如果由其他線程持有,那么申請者會在一個自旋的while循環中等待,直到獲得鎖,或者被中斷,或者超時。
public class SpinLockTest { static int count = 0; static SpinLock lock = new SpinLock(); public static void main(String[] args) throws InterruptedException { lockUp(); System.out.println("Expected result: " + count); } static void lockUp() throws InterruptedException { Thread t1 = new Thread(new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i< 5000000; i++) { count++; } } finally { lock.unlock(); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i< 5000000; i++) { count++; } } finally { lock.unlock(); } } }); t1.start(); t2.start(); t1.join(); t2.join(); } } class SpinLock { private AtomicReferenceowner = new AtomicReference<>(); public void lock() { Thread currentThread = Thread.currentThread(); while (!owner.compareAndSet(null, currentThread)) { } } public void unlock() { Thread currentThread = Thread.currentThread(); owner.compareAndSet(currentThread, null); } }