Lock锁接口(JUC vital)
实现类
- ReentrantLock(可重入锁)
- ReentrantReadWriteLock.ReadLock
- ReentrantReadWriteLock.WriteLock
底层扩展
- FairSync():公平锁,先来后到
- NonfairSync(default mechanism):非公平锁,可以插队
//源码:构造方法
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
使用步骤
- 1.Lock lock = new ReentrantLock();
- 2.lock.lock();//加锁
- 3.lock.unlock();//解锁
- 代码示例:
package com.cyl.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SafeTicketDemo02 {
public static void main(String[] args) {
//并发,多线程同时操作一个资源类,将资源类丢入线程
Ticket02 ticket = new Ticket02();
//@FunctionInterface 函数式接口
// jdk1.8之后使用lambda表达式简化书写:(parameter)->{code}
new Thread(()->{
for (int i = 0; i < 20; i++) ticket.sale();
},"a0").start();
new Thread(()->{
for (int i = 0; i < 20; i++) ticket.sale();
},"a1").start();
new Thread(()->{
for (int i = 0; i < 20; i++) ticket.sale();
},"a2").start();
}
}
//资源类
//Lock锁
class Ticket02{
// 1.属性,方法(OOP思想)
private int ticketNums = 20;
Lock lock = new ReentrantLock();
//卖票的方法
public void sale() {
lock.lock();//加锁
try {//业务代码
if (ticketNums > 0) {
System.out.println(Thread.currentThread().getName()+
"卖出了"+(ticketNums--)+"张票,剩余"+ticketNums);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
##Synchronized与Lock锁的区别
- 1.Synchronized是Java内置的关键字,Lock是Java的一个应用类
- 2.Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
- 3.Synchronized会自动释放锁,Lock需要手动解锁,如果不释放锁,会出现死锁现象
- 4.Synchronized线程b在等待线程a释放锁时,恰好线程a发生阻塞,那么线程b会一直等下去;而Lock锁不一定继续等待,会通过lock.tryLock()方法尝试获取锁
- 5.Synchronized是可重入,非公平锁,不可以中断;Lock是可重入锁,可对锁的状态进行判断,非公平(可以自定义)
- 6.Synchronized适合锁少量的代码同步问题;Lock适合锁大量的同步代码
//源码:构造方法
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
问题重述:生产者和消费者的问题
package com.cyl.PC;
/**
* 线程之间的通信问题(线程交替执行),等待唤醒,通知唤醒
* 单例模式,生产者和消费者,死锁
* A对num进行+1,告诉B之后,B对num进行-1
* */
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//判断是否需要等待,业务,通知
class Data { //数字,资源类
private int num = 0;
//+1
public synchronized void increment() throws InterruptedException {
if (num != 0) {
//等待
this.wait();
}
num ++ ;
System.out.println(Thread.currentThread().getName()+"==>"+num);
//通知其他线程,我+1执行结束了
this.notifyAll();
}
//+2
public synchronized void decrement() throws InterruptedException {
if (num == 0) {
//等待
this.wait();
}
num -- ;
System.out.println(Thread.currentThread().getName()+"==>"+num);
//通知其他线程,我-1执行结束了
this.notifyAll();
}
}
那假设线程变得更多呢?(A,B,C,D…)
线程变多,即就产生了虚假唤醒问题,将if判断改为while循环判断即可。
生产者和消费者问题(JUC解决)
- 传统版本:Synchronized wait notify
- JUC版本:Lock await signal
- 代码实现:
class Data02 { //数字,资源类
private int num = 0;
Lock lock = new ReentrantLock();
//condition:精准通知和唤醒线程
Condition condition = lock.newCondition();
public void decrement() throws InterruptedException {
try {
lock.lock();
//业务代码
while (num == 0) {
//等待
condition.await();
}
//通知其他线程
condition.signalAll();
}catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
- 线程间实现顺序通信
package com.cyl.PC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 线程间通信,实现顺序执行
* A执行完之后通知B,B执行完之后通知C,C执行完通知A
*/
public class C {
public static void main(String[] args) {
Data03 data = new Data03();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printC();
}
},"C").start();
}
}
//资源类
class Data03 {//Lock
private Lock lock = new ReentrantLock();
Condition condition01 = lock.newCondition();//同步监视器
Condition condition02 = lock.newCondition();
Condition condition03 = lock.newCondition();
private int num = 1;//1A 2B 3C
public void printA() {
lock.lock();
try {//业务代码->判断->执行->通知
while(num != 1) {
//等待
condition01.await();
}
System.out.println(Thread.currentThread().getName()+"AA");
//唤醒指定的线程(B)
num = 2;
condition02.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {//业务代码->判断->执行->通知
while(num != 2) {
condition02.await();
}
System.out.println(Thread.currentThread().getName()+"BB");
num = 3;
condition03.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {//业务代码->判断->执行->通知
while (num != 3) {
condition03.await();
}
System.out.println(Thread.currentThread().getName()+"CC");
num = 1;
condition01.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}