2. Lock (锁的)接口

一、 复习synchronized

  他是Java的关键字,是一种同步锁,能够修饰 一个 对象,变量,方法,

   来控制这个所修饰的,被顺序的访问,

1.1 多线程的编程步骤:

   第一:创建一个资源类,属性和操作方法

   第二:创建多线程,调用类里面的操作方法

结合synchronized 锁 和 多线程的编程步骤实现卖票的功能 :(高内聚低耦合)

public class SaleTicket {
    //第二步,创建多个线程,调用资源类的操作方法
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        //具体创建线程的方法是new Thread(new Runnable({ 重写run方法},线程名)
        Thread t1 = new Thread(() -> {
            for(int i =0; i<10;i++){
                ticket.sale();
            }
        },"t1"
        );
        t1.start();
        Thread t2= new Thread(
                 //Lambda 表达式
                () ->{ for (int i = 0; i < 10; i++) {
                    ticket.sale();
                } } ,"t2"
        );
        t2.start();

    }
}



//多线程实现卖票的功能  synchronized方式
class Ticket{ //第一步 资源类 票
    private int num =30; //定义票的数量
    public synchronized void sale(){  //synchronized
        //给这个资源加上锁,防止多线程的错误
        //资源的操作 卖票的方法
        if(num>0){
            System.out.println(Thread.currentThread().getName()+
                    " 卖出了: 1张 还剩下"+(num--)); }
    }
}

 代码执行的时候,t1 和 t2两个线程执行堆叠在一起,这是因为不同线程不同对象启动执行,都可以访问

 二、 Lock接口


为锁和等待条件提供一个框架的接口和类,不同于内置同步和监视器, LOCK是类,可通过类实现同步访问,多个接口实现类:可重入锁等

lock的编程步骤同synchronized

可重入锁的代码定义private final ReentrantLock lock = new ReentrantLock(true);
上锁lock.lock();
解锁lock.unlock();
上锁与解锁中的代码如果出现异常,解锁会执行不了,所以最好加try..finally

import java.util.concurrent.locks.ReentrantLock;

public class LSaleTicket {
    //第二步 创建多个线程,调用资源类的操作方法
    //创建三个线程
    public static void main(String[] args) {
        LTicket ticket = new LTicket();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"AA").start();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"BB").start();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"CC").start();
    }
}

class LTicket {
    private int num = 30; //票数量
    private final ReentrantLock lock = new ReentrantLock(true);  //创建可重入锁
    public void sale() {   //卖票方法
        //上锁
        lock.lock();
        try {
            if(num > 0) { //判断是否有票
                System.out.println(Thread.currentThread().getName()+" :卖出 1张 剩余:"+(num--));
            }
        } finally {
            //解锁
            lock.unlock();
        }
    }
}

2.1 Lock方法 

lock常用接口

public interface Lock {
	void lock();
	void lockInterruptibly() throws InterruptedException;
	boolean tryLock();
	boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
	void unlock();
	Condition newCondition();
}

lock()方法用来获取锁

  • 如果锁已被其他线程获取,则进行等待
  • 发生异常不会自动解锁,需用在 try{}catch{}块中进行
lock.lock();
try{
	//处理任务
}catch(Exception ex){
}finally{
	lock.unlock(); //释放锁
}
 

Condition 类也可以实现等待/通知模式

    关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式,Lock 锁的 newContition()方法返回 Condition 对象,Condition 类也可以实现等待/通知模式

 

用 notify()通知时,JVM 会随机唤醒某个等待的线程, 使用 Condition 类可以进行选择性通知, Condition 比较常用的两个方法:

   1.  await()会使当前线程等待,同时会释放锁,当其他线程调用 signal()时,线程会重新获得锁并继续执行
   2. signal()用于唤醒一个等待的线程

ReentrantLock 是唯一实现了 Lock 接口的类,并且 ReentrantLock 提供了更多的方法
ReentrantLock可重入锁

Reentrant  ReadWriteLock 里面提供了很多丰富的方法,不过最主要的有两个方法:readLock()和 writeLock()用来获取读锁和写锁
writeLock();来获取读锁
readLock();获取写锁

public interface ReadWriteLock {
 Lock readLock();
 Lock writeLock();
}

2.2 两者差异


synchronized与lock的异同:

   1. synchronized是java关键字,内置,而lock不是内置,是一个类,可以实现同步访问

                且 比 synchronized中的方法更加丰富
    2.synchronized不会手动释放锁,而lock需手动释放锁(不解锁会出现死锁,需要在 finally 块中释放锁)
   3. lock等待锁的线程会相应中断,而synchronized不会相应,只会一直等待
   4.  通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到
   5.   Lock 可以提高多个线程进行读操作的效率(当多个线程竞争的时候)

posted @ 2022-03-07 11:20  随遇而安==  阅读(52)  评论(0编辑  收藏  举报