JUC学习
1、 Lock锁
- synchronized
public class SaleTicketDemo01 {
public static void main(String[] args) {
//并发,多个线程操作一个资源
Ticket ticket = new Ticket();
//函数式接口
//创建线程,把资源丢进线程中
//jdk 1.8 lambda表达式 (参数)->{代码}
new Thread(()->{
for (int i = 0; i < 60; i++){
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 60; i++){
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 60; i++){
ticket.sale();
}
},"C").start();
}
}
class Ticket{
private int number = 50;
//synchronized的本质是 队列 + 锁
public synchronized void sale(){
if (number>0) {
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"张票,剩余"+number+"张票");
}
}
}
- Lock
public class SaleTicketDemo02 {
public static void main(String[] args) {
//并发,多个线程操作一个资源
Ticket2 ticket = new Ticket2();
new Thread(() -> { for (int i = 0; i < 60; i++) ticket.sale(); }, "A").start();
new Thread(() -> { for (int i = 0; i < 60; i++) ticket.sale(); }, "B").start();
new Thread(() -> { for (int i = 0; i < 60; i++) ticket.sale(); }, "C").start();
}
}
// lock三部曲
// 1. new ReentrantLock
// 2. lock.lock() //加锁
// 3. finally=> lock.unlock() //解锁
class Ticket2{
private int number = 50;
Lock lock = new ReentrantLock();
public synchronized void sale(){
lock.lock();
try {
//业务代码
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票,剩余" + number + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
synchronized和lock的区别
- synchronized是一个关键字,lock是一个类;
- synchronized不能判断锁的状态,lock可以判断锁的状态;
- synchronized是一个全自动的锁,不用解锁,lock需要手动解锁,如果不解锁,就会死锁;
- synchronized 线程1(获得锁,阻塞),线程2(等待,傻傻的等),lock不一定会等,tryLock。
2、生产者消费者问题
生产者消费者synchronized版
// 生产者和消费者问题,即两个线程去操作同一个资源 number
// 生产者 number++
// 消费者 number--
public class ProductConsumer {
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();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//判断等待 业务 通知 (生产者和消费者三部曲)
class Data{
private int number = 0;
public synchronized void increment() throws InterruptedException {
if (number != 0 ){
//等待
this.wait();
}
number ++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (number == 0){
//等待
this.wait();
}
number --;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
}
存在的问题,上面是两个线程,如果是四个线程呢 ABCD,线程死锁,程序崩溃
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dqeo5eXa-1631506927300)(C:\Users\15067\AppData\Roaming\Typora\typora-user-images\image-20200225134515046.png)]
- 原因
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FeCsKuQn-1631506927302)(C:\Users\15067\AppData\Roaming\Typora\typora-user-images\image-20200225135508385.png)]
- 解决:改成while判断
JUC版生产者消费者问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqM3BKNb-1631506927303)(C:\Users\15067\AppData\Roaming\Typora\typora-user-images\image-20200225140752391.png)]
//Condition + Lock
public class ProAndCsmLock {
public static void main(String[] args) {
Data02 data = new Data02();
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.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断等待 业务 通知 (生产者和消费者三部曲)
class Data02{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
try {
lock.lock();
while (number != 0 ){
//等待
condition.await();
}
number ++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public synchronized void decrement() throws InterruptedException {
try {
lock.lock();
while (number == 0 ){
//等待
condition.await();
}
number --;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition实现精确唤醒锁,具有监视器的功能
// 在多线程下,实现业务A -> 业务B-> 业务C 顺序执行
public class ProAndCsmLock02 {
public static void main(String[] args) {
Print print = new Print();
new Thread(()->{print.printA();},"A").start();
new Thread(()->{print.printB();},"B").start();
new Thread(()->{print.printC();},"C").start();
}
}
//判断等待 业务 通知 (生产者和消费者三部曲)
class Print{
Lock lock = new ReentrantLock();
private int number = 1;
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public void printA(){
try {
lock.lock();
while( number !=1 ){
condition1.await();
}
number = 2;
System.out.println(Thread.currentThread().getName()+"业务A执行");
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
try {
lock.lock();
while( number != 2){
condition2.await();
}
number = 3;
System.out.println(Thread.currentThread().getName()+"业务B执行");
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
try {
lock.lock();
while(number !=3){
condition3.await();
}
number = 1;
System.out.println(Thread.currentThread().getName()+"业务C执行");
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}