synchronized

使用synchronized實現同步有2種方式:

  • 同步方法(靜態與非靜態)
  • 同步程式碼塊

任何Java物件均可作為鎖使用,其中,使用的鎖物件有以下3種:

  • 靜態同步方法中,鎖是當前類的Class物件
  • 非靜態同步方法中,鎖是當前物件this(呼叫該方法的物件)
  • 同步程式碼塊中,瑣是手動配置的物件

同步方法

private synchronized void f()
{
//...
}

同步程式碼塊

private void f()
{
synchronized(this)
{
//...
}
}

Lock

Lock介面中規定了鎖必須實現的一些方法

  • void lock()
  • void unlock()
  • boolean tryLock()
  • boolean tryLock(long time, TimeUnit unit)
  • Condition newCondition()

Lock介面的實現類有ReentarntLockReentrantReadWriteLock2種,它們都提供了非公平鎖和公平鎖2種形式。

ReentrantLock

可重入鎖,執行緒可以重複的獲取已經持有的鎖。

鎖中維護著一個持有計數,來追蹤對lock方法的巢狀呼叫,每次lock計數加1,每次unlock計數減1。

只有持有計數為0時,才釋放鎖。

使用示例

private Lock lock=new ReentrantLock();

private void f()
{
lock.lock();
try
{
// ...
}
finally
{
lock.unlock();
}
}

公平鎖,執行緒排程器將優先(並不保證一定)執行等待時間最長的執行緒。

在建立ReentrantLock時,可以傳入Boolean引數true,建立一個公平鎖。

Lock fairLock=new ReentrantLock(true);

除了使用lock()獲取鎖外,還可以使用tryLock()嘗試獲取鎖,如果成功,返回true,否則,返回false,並且執行緒可以立即離開去做其它事情。

還可以呼叫傳入超時引數。

ReentrantReadWriteLock

可重入讀寫鎖。如果對一個數據結構進行讀操作的次數遠遠大於寫操作的次數,就可以使用讀寫鎖提高效能。

使用示例

private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();// 建立讀寫鎖
private Lock readLock=lock.readLock();// 讀鎖
private Lock writeLock=lock.writeLock();// 寫鎖 // 讀操作加讀鎖
public void read()
{
readLock.lock();
try
{
// ...
}
finally
{
readLock.unlock();
}
} // 寫操作加寫鎖
public void write()
{
writeLock.lock();
try
{
// ...
}
finally
{
writeLock.unlock();
}
}

死鎖

死鎖問題的產生,是由於執行緒A和執行緒B互相持有對方需要獲取的鎖物件導致的

private static final Object lockA=new Object();
private static final Object lockB=new Object(); private void deadLock()
{
Thread t1=new Thread(()->{
synchronized(lockA)
{
sleep(1L);
synchronized(lockB)
{
System.out.println("thread 1");
}
}
}); Thread t2=new Thread(()->{
synchronized(lockB)
{
sleep(1L);
synchronized(lockA)
{
System.out.println("thread 2");
}
}
}); t1.start();
t2.start();
} private void sleep(long timeout)
{
try
{
TimeUnit.SECONDS.sleep(timeout);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}

死鎖問題一旦發生,程式就會掛起。所以,必須避免死鎖的發生,有以下幾個方式

  • 避免在一個執行緒中同時獲取多個鎖
  • 嘗試使用定時鎖(lock.tryLock(timeout)),替代普通鎖機制