多线程--Lock锁

文章目录

Lock锁

在 jdk1.5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,Lock 接口提供了与 synchronized 关键字类似的同步功能,但需要在使用时手动获取锁和释放锁,且在使用上比synchronized更加灵活。

1、使用ReentrantLock实现同步

在这里插入图片描述

案例:

package com.yxl.demo.ThreadTest;

public class test5 {

    public static void main(String[] args) {

        TestDemo thread = new TestDemo();
        Thread t1 = new Thread(thread,"窗口一");
        Thread t2 = new Thread(thread,"窗口二");
        t1.start();
        t2.start();
    }
}

class TestDemo implements Runnable{
    //共享的火车票变量
    private  int count = 100;

    //重寫run方法
    @Override
    public void run() {
        while (count > 0){
            try {
            	//休眠一下 方便出现并发问题
                Thread.sleep(50);
            }catch (Exception e){
                e.getMessage();
            }
            sale();
        }
    }
    //卖票
    public void sale(){
        if(count > 0){
            System.out.println(Thread.currentThread().getName() +"出售 :" +(100 -  count + 1));
            count--;
        }
    }
}

运行结果如下:会发现出现卖重复票的问题

除了 内置锁(Synchronized)解决方案,我们可以使用 Lock锁解决

synchronized的缺陷
synchronized是Java中的一个关键字。

我们知道如果一段代码被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块的时候,其他的线程便只能一直等待,等待获取锁的线程释放锁,而这里获锁的线程释放锁有两种情况:

  1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有;

  2. 线程执行发生异常,此时JVM会让线程自动释放锁。

如果这个获取锁的线程由于I/O或者其他原因(如调用sleep方法)被阻塞了,但是有没有释放锁,其他线程便只能干巴巴地等待,这会很影响执行效率。

因此就需要一种机制可以不让等待的线程一直无限期地等待下去(如只等待一定的时间或者能够响应中断),通过Lock就可以办到。

再如:当有多个线程读取文件时,读操作和写操作会发生冲突,写操作和写操作会发生冲突,但是读操作和读操作不会发生冲突。

如果此时采用synchronized关键字就会出现一个问题:如果多个线程只是进行读操作,所以当一个线程进行读操作时,其他的线程只能等待无法进行读操作。

因此就需要 一种机制使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。

另外,通过Lock可以知道线程有没有成功获取锁,这是synchronized无法办到的。

注意:

  1. Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性,Lock是一个类(接口),通过这个类可以实现同步访问;

  2. 使用synchronized不需要用户手动去释放锁,当synchronized方法或代码块执行完后,系统会自动让线程释放对锁的占用;而Lock则必须要用户手动释放锁,如果没有主动释放,就有可能导致出现死锁。

**使用Lock锁案例 **

package com.yxl.demo.ThreadTest;

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

public class test5 {

    public static void main(String[] args) throws InterruptedException {

        TestDemo thread = new TestDemo();
        Thread t1 = new Thread(thread,"窗口一");
        Thread t2 = new Thread(thread,"窗口二");
        t1.start();
        t2.start();
    }
}

class TestDemo implements Runnable{
    //共享的火车票变量
    private  int count = 100;
    //重寫run方法
    @Override
    public void run() {
               while (count > 0) {
                       sale();
           }
        }
    public  void sale() {
        Lock lock  = new ReentrantLock();
        lock.lock();
        try {
            if (count > 0) {
                System.out.println(Thread.currentThread().getName() + "出售 :" + (100 - count + 1));
                count--;
            }
        }catch (Exception e){
        }finally {
            //一定在finally中释放锁
            lock.unlock();
        }
    }
}

lock.lock() 获取锁
lock.unlock() 释放锁,但要在 finally中使用
lock.trylock() 获取锁 ,也要结合 try catch 一起使用

猜你喜欢

转载自blog.csdn.net/qq_41977838/article/details/105795284