文章参考:https://blog.csdn.net/androidsj/article/details/80239640
锁的实现原理:https://blog.csdn.net/weixin_41240817/article/details/92112665
synchronized详细解析: https://mp.weixin.qq.com/s/g79pBaGIyPh9u5cPfVQJqQ
并发编程juc包学习2-锁
ReentrantLock
ReentrantLock是一个可重入的互斥锁,又被称为”独占锁”。
➣ ReentrantLock锁在同一个时间点只能被一个线程锁持有;而可重入的意思是,
ReentrantLock锁,可以被单个线程多次获取。
➣ ReentrantLock分为”公平锁”和“非公平锁”。它们的区别体现在获取锁的机制
上是否公平以及执行速度上。
➣ ReentrantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的。
ReentrantLock是一个独占锁,在获取锁的之后其所有的操作是线程独享的,其它的线程在没有获取到锁之前都需要进行等待。
condition
是按照条件进行加锁和解锁的类
➣ Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait()、notify()、notifyAll()方法是和”同步锁”/“共享锁”捆绑使用的。
使用
包含了使用ReentrantLock 已经Condition条件
目的:多线程打印abc
/**
* 测试ReentrantLock和Condition
* 作用:按照条件解锁某一个线程,更加方便控制线程之间的协同
*/
public class TestCondition {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
//true表示这是一个公平锁
ReentrantLock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
executorService.execute(() -> {
try {
lock.lock();
//监听c1,当有线程唤醒c1就开始往下走
condition1.await();
System.out.println("b");
//唤醒c2,当有线程监听c2就会继续执行
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
executorService.execute(() -> {
try {
lock.lock();
condition2.await();
System.out.println("c");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
//作为起始入口的第一个执行的线程要放在最后,保证其他已经await后,在进行signal
executorService.execute(() -> {
try {
lock.lock();
System.out.println("a");
condition1.signal();//唤醒c1
}finally {
lock.unlock();
}
});
executorService.shutdown();
}
}
ReadWriteLock
所谓的读写锁指的是有两把锁,在进行数据写入的时候有一把”写锁”,而在进行数据读取的时候有一把”读锁”,很明显写锁一定会实现线程安全同步处理操作,而读锁可以被多个对象读取获得。
➣ 分为读锁和写锁,多个读锁不互斥(共享锁),读锁与写锁互斥,这是由jvm自己控制的,开发者只要上好相应的锁即可;
➣ ReentrantReadWriteLock会使用两把锁来解决问题,一个读锁(多个线程可以同时读),一个写锁(单个线程写)。
➣ ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥,这一特性最为重要, 因为对 于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量;
使用实例
目的:模拟银行多线程存钱和多线程查询的数据一致
/**
* 测试读写锁,模拟银行存取钱
*/
public class TestReadWriteLock {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
//共享同一个账户
Account account = new Account();
//20个存钱线程
for (int i = 0; i < 20; i++) {
executorService.execute(() -> {
account.saveMoney(20);
});
}
//10个查询线程
for (int i = 0; i < 10; i++) {
Future<Integer> submit = executorService.submit(() -> {
return account.readMoney();
});
try {
System.out.println("查询账户" + submit.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executorService.shutdown();
}
}
class Account {
private int money = 10;
private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void saveMoney(int i) {
//获取写锁
ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
//写锁
writeLock.lock();
try {
System.out.println("存入前余额" + money);
this.money = money + i;
System.out.println(Thread.currentThread().getName() + "存入" + i);
System.out.println("存入后余额" + money);
} finally {
writeLock.unlock();
}
}
public int readMoney() {
//同理使用读锁
readWriteLock.readLock().lock();
try {
return money;
} finally {
readWriteLock.readLock().unlock();
}
}
}