lock接口的基本使用(一)

一:lock接口的基本使用

在这里插入图片描述

1.1:使用synchronized关键字实现wait/notify机制

1、业务类

public class MyService {

    private Object lock = new Object();

    public void awaitMethod(){
        try {
            synchronized (lock){
                System.out.println("awaitMethod() start...");
                lock.wait();
                System.out.println("awaitMethod() end...");
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void notifyMethod(){
        synchronized (lock){
            System.out.println("notifyMethod() start...");
            lock.notify();
            System.out.println("notifyMethod() end...");
        }
    }

}

2、测试类

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();

        //注意: 多个线程之间一定要使用的是同一把锁,所以这里不能写成如下:
        // Thread t = new Thread(() -> new MyService().awaitMethod()).start();
        Thread t1 = new Thread(() -> myService.awaitMethod());
        Thread t2 = new Thread(() -> myService.notifyMethod());

        t1.start();
        TimeUnit.SECONDS.sleep(2);
        t2.start();
    }
}

3、控制台

awaitMethod() start...
notifyMethod() start...
notifyMethod() end...
awaitMethod() end...

4、注意点

a. 可以使用任意对象作为锁,但必须保证锁是同一把!
b. 一般都是使用锁去调用wait/notify/notifyAll方法!
c. wait/notify/notifyAll方法,必须在同步代码块中使用,否则会出现异常!
1.2:使用lock锁来实现wait/notify机制

1、业务类

public class MyService {

    //依赖倒转原则
    private Lock lock = new ReentrantLock();
    private Condition condition  = lock.newCondition();

    public void awaitMethod(){
        try {
            lock.lock();
            System.out.println("awaitMethod() start...");
            condition.await(); //会释放锁,await方法必须在lock和unlock中使用
            System.out.println("awaitMethod() end...");
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signalMethod(){
        try {
            lock.lock();
            System.out.println("signalMethod() start...");
            condition.signal(); //signal方法必须在lock和unlock中使用
            System.out.println("signalMethod() end...");
        }finally {
            lock.unlock();
        }
    }

}

2、测试类

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        //1.创建共享资源
        MyService myService = new MyService();

        //2.创建两个线程,分别执行业务类的不同方法
        Thread t1 = new Thread(() -> myService.awaitMethod());
        Thread t2 = new Thread(() -> myService.signalMethod());
        t1.start();
        //3.让main线程休眠2s,防止t2线程先执行.如果t2线程先执行,那么t1线程到时没人唤醒了
        TimeUnit.SECONDS.sleep(2);
        t2.start();
    }
}

3、控制台

awaitMethod() start...
signalMethod() start...
signalMethod() end...
awaitMethod() end...

4、注意点

概述:使用lock锁来实现wait/notify机制,其实和我们使用synchronized关键字实现wait/notify机制很相似
区别如下:
一:synchronized1.等待和唤醒的方法为:wait/notify/notifyAll方法,一般是由锁来调用
2.等待和唤醒的方法必须在同步中使用,否则会出现异常

二:lock中:
1.等待和唤醒的方法为:await/signal/signalAll方法,并且只能由Condition类实例调用
2.等待和唤醒的方法必须在同步中使用(也就是lock.lock(),和lock.unlock()方法中使用),否则会出现异常
3.lock一般都和try..finally结合使用,finally中放lock.unlock();释放锁
1.3:Condition中的等待方法
1.3.1:wait():

一直等待,直到被唤醒或者被中断

1.3.2:await(long time, TimeUnit unit),long awaitNanos(long nanosTimeout)

使当前线程等待直到被唤醒或中断,或者指定的时间过去。
注:指定的时间过去会自动唤醒!但是否往下执行,则还需抢夺cpu的执行权

1、业务类

public class MyService {

    private Lock lock = new ReentrantLock();
    private Condition condition  = lock.newCondition();

    public void awaitMethod(){
        try {
            lock.lock();
            System.out.println("awaitMethod() start time: "+System.currentTimeMillis());
            condition.await(3, TimeUnit.SECONDS); //3秒后会自动被唤醒!
            System.out.println("awaitMethod() end time: "+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

}

2、测试类

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        //注:单个线程执行的时候,直接new MyService()没有关系!,如果多个线程直接new的话,就不是同一把锁了
        new Thread(() -> new MyService().awaitMethod()).start();
    }
}

3、控制台

awaitMethod() start time: 1596360184487awaitMethod() end time: 1596360187488    ②
注: ①中的最后四位: 4487, 和②中的最后四位: 7488, 刚好相差大约3000毫秒,也就是3秒!

注:long awaitNanos(long nanosTimeout) 类似,只不过是纳秒!

1.3.3:boolean awaitUntil(Date deadline)

1、业务类

public class MyService {

    private Lock lock = new ReentrantLock();
    private Condition condition =  lock.newCondition();

    public void waitMethod(){
        try {
            lock.lock();
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND,4); //当前时间后4秒
            System.out.println("await start time: "+System.currentTimeMillis());
            condition.awaitUntil(calendar.getTime());
            System.out.println("await end time: "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

2、测试类

public class Demo {
    public static void main(String[] args) {
        new Thread(() -> new MyService().waitMethod()).start();
    }
}

3、控制台

await start time: 1596373204297
await end time: 1596373208287:刚好相差大约4s左右!
1.3.4:awaitUninterruptibly()

一直等待,直到被唤醒,不会被中断

注:在演示在方法前,我们知道await()的重载方法都是可以被中断的,现在以await()演示一下被中断的效果

1、业务类

public class MyService {

    private Lock lock = new ReentrantLock();
    private Condition condition =  lock.newCondition();

    public void waitMethod(){
        try {
            lock.lock();//①
            System.out.println("await start time: "+System.currentTimeMillis());
            condition.await();
            System.out.println("await end time: "+System.currentTimeMillis());
        } catch (InterruptedException e) {
            System.out.println("我捕获到了异常...");
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

2、测试类

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        Thread t1 = new Thread(() -> myService.waitMethod());
        t1.start();

        //让t1线程先启动
        Thread.sleep(2000);

        t1.interrupt();
        System.out.println("执行了中断t1线程的方法");
    }
}

3、控制台

await start time: 1596373545296
执行了中断t1线程的方法
我捕获到了异常...
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)
	at test.lock.practice01.MyService.waitMethod(MyService.java:17)
	at test.lock.practice01.Demo.lambda$main$0(Demo.java:19)
	at java.lang.Thread.run(Thread.java:748)
注:程序停止了

将上面业务类中的①处,将它改成condition.awaitUninterruptibly()因为该方法不会被interrupt方法给中断,所以不会抛出InterruptedException异常,所以不需要catch去捕获!

4、使用awaitUninterruptibly()之后的控制台

await start time: 1596374052683
执行了中断t1线程的方法

注:程序没有停止,即使调用了中断方法也不会去停止,一直等待,直到被唤醒!!

来自:虽然帅,但是菜的cxy

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值