本文共 3965 字,大约阅读时间需要 13 分钟。
重入锁:在需要进行同步的代码上加上锁定,但不要忘记最后一定要释放,不然会造成永远无法释放,其他线程永远无法进来
公平锁:多个线程按照先后申请顺序获得锁。
非公平锁:多个线程获取锁的顺序并不是按照申请锁的顺序,可能按照CPU获取的先后优先获取锁,有可能造成优先级翻转或饥饿的现象。
/** * 重入锁,必须要手动释放 */ public class L01ReentrantLock { public static void main(String[] args) { ReentrantClass reentrantClass = new ReentrantClass();
new Thread(new Runnable() { @Override public void run() { reentrantClass.method1(); reentrantClass.method2(); } },"t1").start();
new Thread(new Runnable() { @Override public void run() { reentrantClass.method1(); reentrantClass.method2(); } },"t2").start(); } } class ReentrantClass { //重入锁,必须要手动释放,默认非公平锁(false),即按照CPU执行权 private ReentrantLock reentrantLock = new ReentrantLock();
//公平锁,先进先处理 // private ReentrantLock reentrantLock = new ReentrantLock(true);
public void method1() { reentrantLock.lock(); try { System.out.println(Thread.currentThread().getName() + ":method1"); Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + ":method1 end"); } catch (InterruptedException e) { e.printStackTrace(); }finally { reentrantLock.unlock(); } }
public void method2() { reentrantLock.lock(); try { System.out.println(Thread.currentThread().getName() + ":method2"); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + ":method2 end"); } catch (InterruptedException e) { e.printStackTrace(); }finally { reentrantLock.unlock(); } } } |
读写锁:就是实现读写分离的锁,在高并发访问下,尤其是读多写少的情况下,性能高于重入锁。本质就是分成2个锁,读锁可以在多线程并发下访问,但写锁只能一个个的顺序访问。
读读共享、写写互斥、读写互斥。
/** * 读写锁:读读共享、读写互斥、写写互斥 */ public class L02ReentrantReadWriteLock { public static void main(String[] args) { ReadWriteTest readWriteTest = new ReadWriteTest();
Thread t1 = new Thread(new Runnable() { @Override public void run() { readWriteTest.read(); } },"t1");
Thread t2 = new Thread(new Runnable() { @Override public void run() { readWriteTest.read(); } },"t2");
Thread t3 = new Thread(new Runnable() { @Override public void run() { readWriteTest.read(); } },"t3");
Thread t4 = new Thread(new Runnable() { @Override public void run() { readWriteTest.write(); } },"t4");
Thread t5 = new Thread(new Runnable() { @Override public void run() { readWriteTest.write(); } },"t5");
// t1.start(); // t2.start();
t3.start(); t4.start(); t5.start();
} } class ReadWriteTest {
//读写锁:读读共享、读写互斥、写写互斥 private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
//读锁 private ReadLock readLock = readWriteLock.readLock();
//写锁 private WriteLock writeLock = readWriteLock.writeLock();
public void read() { readLock.lock(); try { System.out.println(Thread.currentThread().getName() + ":read"); Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + ":read end"); } catch (InterruptedException e) { e.printStackTrace(); }finally { readLock.unlock(); } }
public void write() { writeLock.lock(); try { System.out.println(Thread.currentThread().getName() + ":write"); Thread.sleep(3000); System.out.println(Thread.currentThread().getName() + ":write end"); } catch (InterruptedException e) { e.printStackTrace(); }finally { writeLock.unlock(); } } } |
不可重入锁:当前线程执行某个方法以及获取了该锁,那么在方法中尝试再次获取锁,就会获取不到被阻塞。
自旋锁:但一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断判断锁是否能够被获取,直到获取到锁才会退出循环。
独享锁:锁每一次只能被一个线程持有。
共享锁:该锁可以被多个线程持有,读写锁中的读锁就是如此。
互斥锁:在访问共享资源之前对其进行加锁操作,在访问完成之后进行解锁操作。保证只有一个线程能够访问被互斥锁保护的资源。
悲观锁:每次都假设最差的情况,如数据库的表锁,行锁都鞥都是在做操作之前就加上独享锁,其他线程无法访问。
乐观锁:假设最好的情况,每次去拿数据都不会认为别人修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有更新这个数据,可以用版本号(mongodb、ES)或CAS算法实现,这样做可以提高吞吐量。
分段锁:是一种锁的设计,并不是具体的一个锁,如ConcurrentHashMap,其并发就是通过分段锁的形式实现的并发操作。加锁的机制是基于粒度更小的分段锁。
偏向锁:同步代码一直被一个线程访问,该线程自动获得锁,降低锁的代价。
轻量级锁:在偏向锁的基础上,还有其他线程访问,其他线程会自旋的形式尝试获取到锁,不会阻塞,提高性能,而偏向锁就升级为轻量级锁。
重量级锁:在轻量级锁的基础上,其他线程在自旋的情况下,不会一直下去,而是自旋到一定的次数,还没有获取到锁,就会进入阻塞。膨胀到一定程度,该锁会升级为重量级锁,其他线程进来就直接阻塞,性能降低。
CAS算法:就是在Atomic系列类讲过的,全称为Compare and Swap(比较并交换),是一种有名的无锁算法。无锁编程,即不使用所的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量同步,所以也叫非阻塞同步。
CAS算法原理:更新一个变量时,只有当变量的预期旧值A和内存地址V当中的实际值相同时,才回将内存地址V对应的值修改为新值B,否则不会执行任何操作。一般情况下是一个自旋的操作,即不断重试。
锁优化建议:避免死锁、减少锁持有的时间、减少锁的粒度、锁的分离、尽量无锁操作,如原子操作(Atomic系列类)、volatile关键字。
转载地址:http://bmmxi.baihongyu.com/