欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java中的锁

程序员文章站 2024-01-09 19:04:52
...

公平锁与非公平锁

公平锁:每个线程获取锁的机会是公平的,按照申请锁的顺序将线程放进一个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锁

相关标签: java