1、公平锁,非公平锁
公平锁:非常公平,不能够插队,必须先来后到
非公平锁:非常不公平,可以插队(默认的都是非公平锁)
public ReentrantLock() { //非公平锁,默认 sync = new NonfairSync(); } public ReentrantLock(boolean fair) {//公平锁,new ReentrantLock(true),参数改为true时为公平锁 sync = fair ? new FairSync() : new NonfairSync(); }2、可重入锁(递归锁)-------所有的锁,都是可重入锁
概念:拿到了最外层的锁之后,就可以拿到了后面的锁(这是自动获得的)。举例:拿到了家门口的钥匙,就可以打开家里房间的门。
synchronized版
package lin.lock; import java.util.concurrent.TimeUnit; //Synchronized========================================================== public class ReenTrantLock_ { public static void main(String[] args) { Phone phone = new Phone(); 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"); } }
执行结果:
lock版
package lin.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //Lock锁========================================================== public class ReenTrantLock_Demo02 { public static void main(String[] args) { Phone2 phone = new Phone2(); new Thread(()->{ phone.sms(); },"A").start(); new Thread(()->{ phone.sms(); },"B").start(); } } class Phone2{ Lock lock = new ReentrantLock(); public void sms(){ lock.lock(); try { System.out.println(Thread.currentThread().getName()+" sms"); call(); //这里也有锁 } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void call(){ lock.lock(); try { System.out.println(Thread.currentThread().getName()+" call"); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } }
执行结果:
细节问题:ReentrantLock版,当调用sms()这个方法时,拿到了lock.lock()这把锁,这时又调用了call()方法,此时又拿到call()的lock.lock()锁,然后lock.unlock()解锁,然后才会去执行sms()中的lock.unlock()解锁!(在lock锁中必须要配对,否则就会死锁)
3、自旋锁(不断地去循环。遍历,迭代知道成功为止)什么是自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
自己写一个基础的自旋锁,小测试:
package lin.lock; import java.util.concurrent.atomic.AtomicReference; public class SpinLockDemo01 { //Thread引用类型,默认的是null AtomicReferenceatomicReference = 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); } }
package lin.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class TestSpinLock { public static void main(String[] args) { // ReentrantLock lock = new ReentrantLock(); // lock.lock(); // lock.unlock(); //底层就是CAS实现的自旋锁 SpinLockDemo01 lock = new SpinLockDemo01(); new Thread(()->{ lock.myLock(); try { TimeUnit.SECONDS.sleep(5); } catch (Exception e) { e.printStackTrace(); }finally { lock.myUnLock(); } },"A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ lock.myLock(); try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); }finally { lock.myUnLock(); } },"B").start(); } }
注意:A线程进来之后,会先拿到这个锁,线程B必须等待。然后A线程自旋,等A线程解锁之后,B线程才有资格解锁。(因为A解锁之后才会释放,释放之后B才有机会进去拿到锁,然后再解锁)
4、死锁死锁是什么?
所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
死锁产生的4个必要条件? 产生死锁的必要条件:互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。
死锁的例子
package lin.lock; import java.util.concurrent.TimeUnit; public class DeadLockDemo01 { public static void main(String[] args) { String lockA = "lockA"; String lockB = "lockB"; new Thread(new MyThread(lockA,lockB),"T1").start(); new Thread(new MyThread(lockB,lockA),"T2").start(); } } class MyThread implements Runnable{ private String lockA; private String lockB; public MyThread(String lockA, String lockB) { this.lockA = lockA; this.lockB = lockB; } @Override public void run() { synchronized(lockA){ System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>"+lockB); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB){ System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>"+lockA); } } } }
结果:
遇到死锁,如何解决问题(因为在控制台中,没有显示任何的异常,只是单纯的卡着程序不懂而已,如何排查错误!!!)
- 使用 jps -l 定位进程号(前面的一串数字就是进程号)
- 使用 jstack 进程号 找到死锁问题
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)