一、公平锁与非公平锁
公平锁:加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
非公平锁:加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
非公平锁性能比公平锁高5~10倍,因为公平锁需要在多核的情况下维护一个队列。Java中的ReentrantLock 默认的lock()方法采用的是非公平锁。通过调用有参构造设置是否为公平与非公平锁
二、可重入锁(递归锁)
1.广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。ReentrantLock和synchronized都是可重入锁
2.特点:获取到外面的锁,就能拿到里面的锁(自动获取;就像自己家一样,拿钥匙开门之后,进卧室不用开锁)
3.代码:
public class MyDemo { public static void main(String[] args) { testLock(); } public static void testSynchronized() { Phone phone = new Phone(); new Thread(() -> { phone.sms(); }, "A").start(); new Thread(() -> { phone.sms(); }, "B").start(); } public static void testLock() { Phone2 phone = new Phone2(); new Thread(() -> { phone.sms(); }, "A").start(); new Thread(() -> { phone.sms(); }, "B").start(); } } class Phone { public synchronized void sms() { System.out.println(Thread.currentThread().getName() + "sms"); call(); // 这里也有锁 } public synchronized void call() { System.out.println(Thread.currentThread().getName() + "call"); } } class Phone2 { Lock lock = new ReentrantLock(); public void sms() { lock.lock(); // 细节问题:lock.lock(); lock.unlock(); // lock 锁必须配对,否则就会死在里面 lock.lock(); try { System.out.println(Thread.currentThread().getName() + "sms"); call(); // 这里也有锁 } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); lock.unlock(); } } public void call() { lock.lock(); try { System.out.println(Thread.currentThread().getName() + "call"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
三、自旋锁
1.是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。
2.在CAS中,Unsafe类里面的方法getAndAddInt()里面就是实现的自旋锁
代码:
public class MyDemo { AtomicReference<Thread> atomicReference = new AtomicReference<>(); // 加锁 public void myLock() { Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName() + "==> mylock"); // 自旋锁 while (!atomicReference.compareAndSet(null, thread)) { } } // 解锁 public void myUnLock() { Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName() + "==> myUnlock"); atomicReference.compareAndSet(thread, null); } public static void main(String[] args) throws InterruptedException { MyDemo lock = new MyDemo(); new Thread(() -> { lock.myLock(); try { TimeUnit.SECONDS.sleep(5); } catch (Exception e) { e.printStackTrace(); } finally { lock.myUnLock(); } }, "T1").start(); TimeUnit.SECONDS.sleep(1); new Thread(() -> { lock.myLock(); try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } finally { lock.myUnLock(); } }, "T2").start(); } }
四、死锁
1.死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去
2.死锁产生的必要条件:
互斥条件、请求和保持条件、不剥夺条件、环路等待条件
3.死锁产生的原因:
竞争不可抢占性资源(或竞争可消耗资源)、进程推进顺序不当
4.避免与解决死锁的算法:死锁预防(有序资源分配法、银行家算法) 解决死锁(死锁预防、死锁避免、死锁检测和解除)
5.java中发生死锁的查看方式
1.运行发生死锁的代码
2.在程序运行时,使用 jps -l查看当前进程号
3.使用jstack 进程号找到死锁问题
原文:https://www.cnblogs.com/jenne-blog/p/13058083.html