JAVA多线程(6):Lock锁

一、概念

Lock类是java.util.concurrent.locks下,可以和synchronized实现同样功能的线程锁。二者区别:

1.Sychronized:隐式锁

可以锁:(1)同步代码块;(2)同步方法

2.Lock:是显示锁

注意:需要通过lock.lock()上锁,并且必须在finally内通过lock.unlock方法释放锁。
 

二、lock解决实例

1.出现多线程共享变量访问问题

package com.algorithm.learn.test.JUC;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Administrator on 2020/1/16.
 */
public class TestLock {
    public static void main(String[] args) {
        Ticket ticket=new Ticket();
        new Thread(ticket,"1号窗口").start();
        new Thread(ticket,"2号窗口").start();
        new Thread(ticket,"3号窗口").start();
    }
}

class  Ticket implements Runnable{
    private int tick=100;
 
    @Override
    public void run() {
        while (true){

            if(tick>0){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"完成售票,余票为:"+ --tick);
            }

        }
    }
}

结果:
...
1号窗口完成售票,余票为:6
2号窗口完成售票,余票为:5
3号窗口完成售票,余票为:6
3号窗口完成售票,余票为:4
2号窗口完成售票,余票为:3
1号窗口完成售票,余票为:2
3号窗口完成售票,余票为:0
2号窗口完成售票,余票为:1
1号窗口完成售票,余票为:-1

2.添加lock解决

package com.algorithm.learn.test.JUC;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Administrator on 2020/1/16.
 */
public class TestLock {
    public static void main(String[] args) {
        Ticket ticket=new Ticket();
        new Thread(ticket,"1号窗口").start();
        new Thread(ticket,"2号窗口").start();
        new Thread(ticket,"3号窗口").start();
    }
}

class  Ticket implements Runnable{
    private int tick=100;
    private Lock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
            //1.上锁
            lock.lock();

            try {
                if(tick>0){
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"完成售票,余票为:"+ --tick);
                }
            }finally {
                //3.解锁:一定在finally里
                lock.unlock();
            }

        }
    }

//    @Override
//    public void run() {
//        while (true){
//
//            if(tick>0){
//                try {
//                    Thread.sleep(200);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                System.out.println(Thread.currentThread().getName()+"完成售票,余票为:"+ --tick);
//            }
//
//        }
//    }
}

结果:
...
3号窗口完成售票,余票为:6
1号窗口完成售票,余票为:5
2号窗口完成售票,余票为:4
2号窗口完成售票,余票为:3
3号窗口完成售票,余票为:2
3号窗口完成售票,余票为:1
1号窗口完成售票,余票为:0

3.生产者消费者实例(等待唤醒)

(1)synchronized 实现生产者和消费者实例,有虚假唤醒

package com.algorithm.learn.test.JUC;

/**
 * Created by Administrator on 2020/1/16.
 */
public class TestProductorAndConsumer {

    public static void main(String[] args) {
        Clerk clerk=new Clerk();

        Producer producer=new Producer(clerk);
        Consumer consumer=new Consumer(clerk);

        new Thread(producer,"生产者A").start();
        new Thread(consumer,"消费者B").start();
    }
}

/**
 * 店员
 */
class Clerk{
    private int product=0;

    //进货
    public synchronized void get(){
        if(product>=10){
            System.out.println("产品已满!");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            System.out.println(Thread.currentThread().getName()+":"+ ++product);
            this.notifyAll();
        }
    }

    //卖货
    public synchronized void sale(){
        if(product<=0){
            System.out.println("产品已没有了!");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            System.out.println(Thread.currentThread().getName()+":"+ --product);
            this.notifyAll();
        }
    }
}

/**
 * 生产者
 */
class Producer implements Runnable{

    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.get();
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}

结果:

生产者A:1
生产者A:2
生产者A:3
生产者A:4
生产者A:5
生产者A:6
生产者A:7
生产者A:8
生产者A:9
生产者A:10
产品已满!
消费者B:9
消费者B:8
消费者B:7
消费者B:6
消费者B:5
消费者B:4
消费者B:3
消费者B:2
消费者B:1
消费者B:0
产品已没有了!
生产者A:1
生产者A:2
生产者A:3
生产者A:4
生产者A:5
生产者A:6
生产者A:7
生产者A:8
生产者A:9
消费者B:8
消费者B:7
消费者B:6
消费者B:5
消费者B:4
消费者B:3
消费者B:2
消费者B:1
消费者B:0

(2)synchronized解决虚假唤醒(使用while替换if)

package com.algorithm.learn.test.JUC;

/**
 * Created by Administrator on 2020/1/16.
 */
public class TestProductorAndConsumer {

    public static void main(String[] args) {
        Clerk clerk=new Clerk();

        Producer producer=new Producer(clerk);
        Consumer consumer=new Consumer(clerk);

        new Thread(producer,"生产者A").start();
        new Thread(consumer,"消费者B").start();
        new Thread(producer,"生产者C").start();
        new Thread(consumer,"消费者D").start();
    }
}

/**
 * 店员
 */
class Clerk{
    private int product=0;

    //进货
    public synchronized void get(){
        while(product>=1){
            System.out.println("产品已满!");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //else{
//            System.out.println(Thread.currentThread().getName()+":"+ ++product);
//            this.notifyAll();
//        }
        System.out.println(Thread.currentThread().getName()+":"+ ++product);
        this.notifyAll();
    }

    //卖货
    public synchronized void sale(){
        while(product<=0){
            System.out.println("缺货!");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//        else {
//            System.out.println(Thread.currentThread().getName()+":"+ --product);
//            this.notifyAll();
//        }
        System.out.println(Thread.currentThread().getName()+":"+ --product);
        this.notifyAll();
    }
}

/**
 * 生产者
 */
class Producer implements Runnable{

    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            //添加延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.get();
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            //添加延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.sale();
        }
    }
}

结果:
生产者A:1
消费者D:0
生产者C:1
消费者B:0
生产者A:1
消费者D:0
生产者C:1
消费者B:0
缺货!
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
缺货!
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
缺货!
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者A:1
消费者D:0
缺货!
生产者C:1
消费者B:0
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者C:1
消费者B:0
缺货!
生产者A:1
消费者D:0
生产者C:1
消费者B:0
生产者A:1
消费者D:0
缺货!
缺货!

(3)Lock实现生产者和消费者实例

Condition对象中,await、signal和signalAll分别对应Synchronized中wait、notify和notifyAll方法。

package com.algorithm.learn.test.JUC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Administrator on 2020/1/16.
 */
public class TestProductorAndConsumer {

    public static void main(String[] args) {
        Clerk clerk=new Clerk();

        Producer producer=new Producer(clerk);
        Consumer consumer=new Consumer(clerk);

        new Thread(producer,"生产者A").start();
        new Thread(consumer,"消费者B").start();
        new Thread(producer,"生产者C").start();
        new Thread(consumer,"消费者D").start();
    }
}

/**
 * 店员
 */
class Clerk{
    private int product=0;

    private Lock lock=new ReentrantLock();

    private Condition condition=lock.newCondition();

    //进货
    public void get(){
        lock.lock();

        try {
            while(product>=1){  //为了避免虚假唤醒问题,应该总是使用在循环中
                System.out.println("产品已满!");
                try {
//                    this.wait();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //else{
//            System.out.println(Thread.currentThread().getName()+":"+ ++product);
//            this.notifyAll();
//        }
            System.out.println(Thread.currentThread().getName()+":"+ ++product);
//            this.notifyAll();
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }

    //卖货
    public void sale(){

        lock.lock();
        try {
            while(product<=0){  //为了避免虚假唤醒问题,应该总是使用在循环中
                System.out.println("缺货!");
                try {
//                    this.wait();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
//        else {
//            System.out.println(Thread.currentThread().getName()+":"+ --product);
//            this.notifyAll();
//        }
            System.out.println(Thread.currentThread().getName()+":"+ --product);
//            this.notifyAll();
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }
}

/**
 * 生产者
 */
class Producer implements Runnable{

    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            //添加延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.get();
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            //添加延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.sale();
        }
    }
}

结果:
...
生产者C:1
产品已满!
消费者D:0
缺货!
生产者A:1
消费者B:0
生产者C:1
消费者B:0
生产者A:1
消费者D:0
生产者C:1
产品已满!
消费者B:0
缺货!
生产者A:1
消费者D:0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值