java 锁
1. 公平锁
指多个线程按照请求锁的顺序来获取锁,类似排队打饭,先来后到。
公平锁就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空或者当前时等待队列的第一个,就占有锁,否则就加入等待队列中,以后会按照FIFO(先进先出)的规则从队列中去到自己
2.非公平锁
是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请锁的线程优先获取锁。在高并发的情况下,可能会造成优先级反转或者饥饿现象
非公平锁比较粗鲁,上来先尝试占有锁,如果尝试失败,就再采取类似于公平锁的那种方式。
非公平锁的优点在于吞吐量比公平锁大
对于Synchronized而言,也是一种非公平锁
并发包中的ReentrantLock可以指定构造函数的boolean 类型来得到公平锁或者非公平锁,默认非公平锁
Lock a = new ReentrantLock(true);//公平锁Lock b = new ReentrantLock(false);//非公平锁Lock c = new ReentrantLock();//默认非公平锁
3. 可重入锁 (又名递归锁)
指的时同一个线程外层函数获取锁后,内层递归函数仍然能获取该锁的代码,在同一个线程的外层方法获取锁的时候,在进入内层方法或自动获取锁。也就是说 线程可以进入任何一个它已经拥有锁所同步的代码块。
如下代码,可重入锁的意思就是,当线程获取了method01的锁后,里面再访问加锁的method02时,无需再次获取method02的锁,默认有这个锁,同上来说,你有了进你家大门钥匙,那么你就可以去你家厕所。
public syncronized void method01(){method02();}public syncronized void method02(){}
下面代码执行结果:
set 的进程信息:Thread-0
get 的进程信息:Thread-0
set 的进程信息:Thread-1
get 的进程信息:Thread-1
虽然set也加锁了,但是get得到锁后,相当于也得到了set的锁
package com.bowen;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;class TestReentantLock implements Runnable{Lock lock = new ReentrantLock();@Overridepublic void run() {get();}public void get(){lock.lock();try {set();System.out.println("get 的进程信息:"+Thread.currentThread().getName());}finally{lock.unlock();}}public void set(){lock.lock();try {System.out.println("set 的进程信息:"+Thread.currentThread().getName());}finally{lock.unlock();}}}public class TestLock {public static void main(String[] args) {TestReentantLock a = new TestReentantLock();Thread t1 = new Thread(a);Thread t2 = new Thread(a);t1.start();t2.start();}}
4. 自旋锁(spinlock)
是指尝试获取锁的线程不会立即阻塞,而是采取循环的方式去尝试获取锁。这样好处时减少线程上下文切换的消耗,缺点是会循环消耗CPU .
典型例子:unsafe.getAndAddInt方法
public final int getAndAddInt(Object var1, long var2, int var4){int var5;do{var5 = this.getIntVolatile(var1, var2);}while(!this.compareAndSwapInt(var1, var2, var5+var4));return var5;}
手写自旋锁
//自旋锁class TestSpinLock{AtomicReference<Thread> atomicReference = new AtomicReference<>();public void myLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName() +"come in lock~!");while(!atomicReference.compareAndSet(null, thread)){}}public void myUnLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName() +"come in unlock~!");atomicReference.compareAndSet(thread, null);}}public class TestLock {public static void main(String[] args) {// TestReentantLock a = new TestReentantLock();// Thread t1 = new Thread(a);// Thread t2 = new Thread(a);// t1.start();// t2.start();TestSpinLock testSpinLock = new TestSpinLock();new Thread(()->{testSpinLock.myLock();try {TimeUnit.SECONDS.sleep(5);}catch (InterruptedException e){}testSpinLock.myUnLock();},"AA").start();new Thread(()->{testSpinLock.myLock();try {TimeUnit.SECONDS.sleep(5);}catch (InterruptedException e){}testSpinLock.myUnLock();},"BB").start();}}//结果AAcome in lock~!BBcome in lock~!AAcome in unlock~!BBcome in unlock~!
5. 独占锁(写锁)
指该锁一次只能被一个线程持有。对ReentrantLock和ASynchronized 是独占锁
6. 共享锁(读锁)
指该锁可被多个线程所持有,对ReentrantReadWriteLock其读锁是共享锁,写锁是独占锁,
读的共享锁可以保证并发读是非常高效的,读写,写读,写写的过程互斥