java中的锁有 公平锁和非公平锁 ,可重入锁,自旋锁,读写锁(独占锁/写锁,共享锁/读锁,互斥锁)
1.公平锁和非公平锁 :公平锁就是线程先来先到,非公平锁可能出现某个线程长时间获取不到锁的情况,会出现线程饥饿。非公平锁优点是吞吐量大
常见的synchronized也是可重入锁,非公平锁
2.自旋锁:用while方式尝试获取锁,减少了线程切换的的消耗,缺点循环会消耗CPU,CAS就是使用自旋锁实现的
3.可重入锁:线程获取方法外部锁后,进入该方法内部可以自动获取该锁的代码,可以避免死锁
4.独占锁:一次只能被一个线程持有。ReentrantLock 和synchronized都是独占锁
5.共享锁:该线程可以被多个线程共同持有 R
ReentrantLock 可重入锁,又名递归锁 ReentrantLock 有公平锁和非公平锁两种构造
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
可重入锁代码验证 synchronized版
/*输出如下 原因:t1 获取了sendSms方法 虽然内部t1sendMail加锁, *t1 依然可以获取内部方法的锁 原因两个方法是同一把锁 *需要注意的是 reentrantLock.lock();需要和reentrantLock.unlock();成对使用 *否则第二个线程将无法进入get方法,输出如下 *t1sendSms *t1sendMail *t2sendSms *t2sendMail *---------以上是synchronized版,下面是reentrantLock版------------- *Thread-0get *Thread-0set * */ /** 正常锁配对使用输出 * t1sendSms * t1sendMail * t2sendSms * t2sendMail * ---------以上是synchronized版,下面是reentrantLock版------------- * Thread-0get * Thread-0set * Thread-1get * Thread-1set */ package com.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; class Phone implements Runnable { public synchronized void sendSms() { System.out.println(Thread.currentThread().getName() + "sendSms"); sendMail(); } public synchronized void sendMail() { System.out.println(Thread.currentThread().getName() + "sendMail"); } ReentrantLock reentrantLock = new ReentrantLock(); @Override public void run() { get(); } public void get() { reentrantLock.lock(); reentrantLock.lock(); try { System.out.println(Thread.currentThread().getName() + "get"); set(); } finally { reentrantLock.unlock(); reentrantLock.unlock(); } } public void set() { reentrantLock.lock(); try { System.out.println(Thread.currentThread().getName() + "set"); } finally { reentrantLock.unlock(); } } } /** * @author liuxu * @date 2021/11/13 15:48 */ public class ReentrantLockDemo { public static void main(String[] args) throws InterruptedException { Phone phone = new Phone(); new Thread(() -> { phone.sendSms(); }, "t1").start(); new Thread(() -> { phone.sendSms(); }, "t2").start(); TimeUnit.SECONDS.sleep(3); System.out.println("---------以上是synchronized版,下面是reentrantLock版-------------"); Thread t3 = new Thread(phone); Thread t4 = new Thread(phone); t3.start(); t4.start(); } }
递归锁代码验证
package com.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; /** * 输出如下 锁生效,可以做到线程安全 * 线程:AAA来了 * 线程:AAA解锁 * 线程:BBB来了 * ------BBB---- * 线程:BBB解锁 * @author liuxu * @date 2021/11/13 16:44 */ public class SpinLockDemo { AtomicReference<Thread> reference =new AtomicReference<>(); public void lock(){ Thread thread=Thread.currentThread(); System.out.println("线程:"+thread.getName()+"来了"); while (!reference.compareAndSet(null,thread)){ } } public void unlock(){ Thread thread=Thread.currentThread(); reference.compareAndSet(thread,null); System.out.println("线程:"+thread.getName()+"解锁"); } public static void main(String[] args) { SpinLockDemo spinLockDemo = new SpinLockDemo(); new Thread(()->{ spinLockDemo.lock(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }finally { spinLockDemo.unlock(); } },"AAA").start(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ spinLockDemo.lock(); try { System.out.println("------BBB----"); } catch (Exception e) { e.printStackTrace(); }finally { spinLockDemo.unlock(); } },"BBB").start(); } }