java中的鎖

公平鎖與非公平鎖

公平鎖:每個線程獲取鎖的機會是公平的,按照申請鎖的順序將線程放進一個FIFO隊列中,誰先申請鎖誰就先獲取鎖,每次有線程來搶佔鎖的時候,都會檢查有沒有等待隊列,如果有,則將該線程加入等待隊列

非公平鎖:線程獲取鎖的機會是不公平的,獲取鎖的線程會隨機搶佔

synchronized實現的鎖是一種非公平鎖,公平鎖可以通過ReentrantLock來實現,同時ReentrantLock也可以實現非公平鎖

// 默認是非公平鎖
Lock lock = new ReentrantLock();
 //public ReentrantLock() {
 //     sync = new NonfairSync();
 //}
 
 // 公平鎖
 Lock lock = new ReentrantLock(true);

可重入鎖

可重入鎖指在同一個線程中外部方法持有的鎖可以被內部方法獲取

synchronized和ReentrantLock都是可以實現可重入鎖

  • synchronized實現的可重入鎖

    public class TestReEntryLock {
    public synchronized void set() {
    System.out.println(Thread.currentThread().getName()+“set”);
    get();
    }

      public synchronized void get() {
      	System.out.println(Thread.currentThread().getName()+"get");
      	set();
      }
      
      public static void main(String[] args) {
      	TestReEntryLock lock = new TestReEntryLock();
      	new Thread(()->{
      		lock.set();
      	},"t1").start();
      }
    

    }

  • ReentrantLock

    public class TestReEntryLock {

      Lock lock = new ReentrantLock();
       public  void set() {
      	 try {
      		lock.lock();
      		System.out.println(Thread.currentThread().getName()+"\t set");
      		get();
      	} finally {
      		lock.unlock();
      	}
       }
       public  void get() {
      	 try {
      		lock.lock();
      		System.out.println(Thread.currentThread().getName()+"\t get");
      	} finally {
      		lock.unlock();
      	}
       }
      public static void main(String[] args) {
      	TestReEntryLock lock = new TestReEntryLock();
      	new Thread(()->{
      		lock.set();
      	},"t1").start();
      }
    

    }

讀寫鎖

支持共享讀,不支持共享讀寫,和寫。也就是說支持同時讀,但是不支持同時寫。這種鎖可以提高讀的併發性

public class WriteAndReadLock {
		
	ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
	
	// 寫操作
	public void write() {
		rwl.writeLock().lock();
		System.out.println(Thread.currentThread().getName()+"正在寫");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		rwl.writeLock().unlock();
		System.out.println(Thread.currentThread().getName()+"寫已經完成");
	}
	// 讀操作
	public void read() {
		rwl.readLock().lock();
		System.out.println(Thread.currentThread().getName()+"正在讀");
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"讀已經完成");
		rwl.readLock().unlock();
	}
	public static void main(String[] args) {
		WriteAndReadLock wad = new WriteAndReadLock();
		for (int i = 0; i < 3; i++) {
			new Thread(()->{
				wad.write();
			}).start();
		}
		for (int i = 0; i < 3; i++) {
			new Thread(()->{
				wad.read();
			}).start();
		}
	}
}

結果:

Thread-0正在寫

Thread-0寫已經完成

Thread-1正在寫

Thread-1寫已經完成

Thread-2正在寫

Thread-2寫已經完成

Thread-3正在讀

Thread-4正在讀

Thread-5正在讀

Thread-3讀已經完成

Thread-4讀已經完成

Thread-5讀已經完成

結論: 每個線程寫操作不能被其它操作所打斷,不支持共享寫。讀操作支持共享讀

自旋鎖

自旋鎖在沒有獲取到鎖的情況下不會馬上將線程阻塞,而是不斷嘗試獲取鎖

public class RoteBySelf {

	private AtomicReference<Thread> ar = new AtomicReference<Thread>();
	
	// 手寫一個自旋鎖
	public void lock() {
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName()+"\t 嘗試獲取鎖");
		// 如果是第一次則獲取鎖成功,跳出while循環
		while(!ar.compareAndSet(null,thread)) {
		}
		System.out.println(thread.getName()+"\t 獲取鎖成功");
	}
	
	public void unlock() {
		Thread thread = Thread.currentThread();
		ar.compareAndSet(thread, null);
		System.out.println(thread.getName()+"\t 釋放鎖成功");
	}
}

死鎖

死鎖是多個線程爭搶共享資源導致互相等待的一種狀態,如果沒有外力驅使,那麼該狀態會一直存在。

產生死鎖的條件:

  • 互斥:一個資源要麼被搶佔,要麼可用,必須是臨界資源
  • 請求和保持:線程請求到資源後,繼續申請資源,並且保持原來所持有的資源
  • 不可搶佔:已經被分配的資源不可被搶佔
  • 環路等待:線程之間互相等待對方釋放所持有的資源
public class DeadDemo implements Runnable{
	
	private Account from;
	private Account to;
	private int amount;
	public DeadDemo(Account from, Account to, int amount) {
		this.from = from;
		this.to = to;
		this.amount = amount;
	}
	public void run() {
		synchronized(from) {
			synchronized (to) {
				from.amount = from.amount-amount;
				to.amount = to.amount+10;
				System.out.println("success");
			}
		}
	}
	public static void main(String[] args) {
		Account a1 = new Account();
		Account a2 = new Account();
		new Thread(new DeadDemo(a1,a2,10)).start();
		new Thread(new DeadDemo(a2,a1,10)).start();
	}
}
class Account{
	 int amount;
}

我的博客:java鎖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章