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锁](http://www.handerh.top/2019/09/04/java%E4%B8%AD%E7%9A%84%E9%94%81/)    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值