计算机网站建设方向,2021半夜好用的网站,不知道怎么选,软件开发文档编制规范Object中对内置锁进行操作的一些方法#xff1a; Java内置锁通过synchronized关键字使用#xff0c;使用其修饰方法或者代码块#xff0c;就能保证方法或者代码块以同步方式执行. 内置锁使用起来非常方便#xff0c;不需要显式的获取和释放#xff0c;任何一个对象都能作为…Object中对内置锁进行操作的一些方法 Java内置锁通过synchronized关键字使用使用其修饰方法或者代码块就能保证方法或者代码块以同步方式执行. 内置锁使用起来非常方便不需要显式的获取和释放任何一个对象都能作为一把内置锁。使用内置锁能够解决大部分的同步场景。“任何一个对象都能作为一把内置锁”也意味着出现synchronized关键字的地方都有一个对象与之关联具体说来 当synchronized作用于普通方法是锁对象是this当synchronized作用于静态方法是锁对象是当前类的Class对象当synchronized作用于代码块时锁对象是synchronized(obj)中的这个obj。wait()系列 wait()系列方法的作用是使当前已经获得该对象锁的线程进入等待状态并且释放该对象的锁。 notify()系列 notify()系列方法的作用是唤醒那些正在等待该对象锁的线程使其继续运行。 基于wait() notify()机制我们可以实现一个简易的生产者-消费者模型。 大体思路如下一个生产者线程负责向一个仓库中存放put物品一个消费者线程负责从仓库中取出get物品。 public class Warehouse {private QueueInteger queue;private int capacity;public Warehouse(int capacity) {this.capacity capacity;queue new LinkedList();}public synchronized void put(int num) {if (queue.size() capacity) {try {System.out.println(Thread.currentThread().getName() , put full wait);wait();} catch (InterruptedException e) {e.printStackTrace();}}queue.add(num);System.out.println(Thread.currentThread().getName() , put : num , queue - queue);notifyAll();}public synchronized int get() {if (queue.isEmpty()) {try {System.out.println(Thread.currentThread().getName() , get empty wait);wait();} catch (InterruptedException e) {e.printStackTrace();}}int num queue.poll();System.out.println(Thread.currentThread().getName() , get : num , queue - queue);notifyAll();return num;}
} public static void main(String[] args) {Warehouse warehouse new Warehouse(4);Random random new Random();new Thread(new Runnable() {Overridepublic void run() {while (true) {warehouse.put(random.nextInt(10));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}, 生产者-01).start();new Thread(new Runnable() {Overridepublic void run() {while (true) {warehouse.get();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}}, 消费者-01).start();} 显式锁 内置锁这么好用为什么还需多出一个显式锁呢因为有些事情内置锁是做不了的比如 我们想给锁加个等待时间超时时间超时还未获得锁就放弃不至于无限等下去我们想以可中断的方式获取锁(线程可以被打断)这样外部线程给我们发一个中断信号就能唤起等待锁的线程我们想为锁维持多个等待队列比如一个生产者队列一个消费者队列一边提高锁的效率。显式锁(ReentrantLock)正式为了解决这些灵活需求而生。ReentrantLock的字面意思是可重入锁可重入的意思是线程可以同时多次请求同一把锁而不会自己导致自己死锁。下面是内置锁和显式锁的区别 可定时RenentrantLock.tryLock(long timeout, TimeUnit unit)提供了一种以定时结束等待的方式如果线程在指定的时间内没有获得锁该方法就会返回false并结束线程等待。 可中断你一定见过InterruptedException很多跟多线程相关的方法会抛出该异常这个异常并不是一个缺陷导致的负担而是一种必须或者说是一件好事。可中断性给我们提供了一种让线程提前结束的方式而不是非得等到线程执行结束这对于要取消耗时的任务非常有用。对于内置锁线程拿不到内置锁就会一直等待除了获取锁没有其他办法能够让其结束等待。RenentrantLock.lockInterruptibly()给我们提供了一种以中断结束等待的方式。 条件队列(condition queue)线程在获取锁之后可能会由于等待某个条件发生而进入等待状态内置锁通过Object.wait()方法显式锁通过Condition.await()方法进入等待状态的线程会挂起并自动释放锁这些线程会被放入到条件队列当中。synchronized对应的只有一个条件队列而ReentrantLock可以有多个条件队列多个队列有什么好处呢请往下看。 条件谓词线程在获取锁之后有时候还需要等待某个条件满足才能做事情比如生产者需要等到“缓存不满”才能往队列里放入消息而消费者需要等到“缓存非空”才能从队列里取出消息。这些条件被称作条件谓词线程需要先获取锁然后判断条件谓词是否满足如果不满足就不往下执行相应的线程就会放弃执行权并自动释放锁。使用同一把锁的不同的线程可能有不同的条件谓词如果只有一个条件队列当某个条件谓词满足时就无法判断该唤醒条件队列里的哪一个线程但是如果每个条件谓词都有一个单独的条件队列当某个条件满足时我们就知道应该唤醒对应队列上的线程内置锁通过Object.notify()或者Object.notifyAll()方法唤醒显式锁通过Condition.signal()或者Condition.signalAll()方法唤醒。这就是多个条件队列的好处。 使用内置锁时对象本身既是一把锁又是一个条件队列使用显式锁时RenentrantLock的对象是锁条件队列通过RenentrantLock.newCondition()方法获取多次调用该方法可以得到多个条件队列。 一个使用显式锁的典型示例如下 // 显式锁的使用示例
ReentrantLock lock new ReentrantLock();// 获取锁这是跟synchronized关键字对应的用法。
lock.lock();
try{// your code
}finally{lock.unlock();
}// 可定时超过指定时间为得到锁就放弃
try {lock.tryLock(10, TimeUnit.SECONDS);try {// your code}finally {lock.unlock();}
} catch (InterruptedException e1) {// exception handling
}// 可中断等待获取锁的过程中线程线程可被中断
try {lock.lockInterruptibly();try {// your code}finally {lock.unlock();}
} catch (InterruptedException e) {// exception handling
}// 多个等待队列具体参考[ArrayBlockingQueue](https://github.com/CarpenterLee/JCRecipes/blob/master/markdown/ArrayBlockingQueue.md)
/** Condition for waiting takes */
private final Condition notEmpty lock.newCondition();
/** Condition for waiting puts */
private final Condition notFull lock.newCondition(); 注意上述代码将unlock()放在finally块里这么做是必需的。显式锁不像内置锁那样会自动释放使用显式锁一定要在finally块中手动释放如果获取锁后由于异常的原因没有释放锁那么这把锁将永远得不到释放将unlock()放在finally块中保证无论发生什么都能够正常释放。 内置锁能够解决大部分需要同步的场景只有在需要额外灵活性是才需要考虑显式锁比如可定时、可中断、多等待队列等特性。 显式锁虽然灵活但是需要显式的申请和释放并且释放一定要放到finally块中否则可能会因为异常导致锁永远无法释放这是显式锁最明显的缺点。 综上当需要同步时请优先考虑更安全的更易用的隐式锁。 package com.imooc.locks;import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Task {private final Lock lock new ReentrantLock();private final Condition addCondition lock.newCondition();private final Condition subCondition lock.newCondition();private static int num 0;private ListString lists new LinkedListString();public void add() {lock.lock();try {while(lists.size() 10) {//当集合已满,则添加线程等待addCondition.await();}num;lists.add(add Banana num);System.out.println(The Lists Size is lists.size());System.out.println(The Current Thread is Thread.currentThread().getName());System.out.println();this.subCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {//释放锁lock.unlock();}}public void sub() {lock.lock();try {while(lists.size() 0) {//当集合为空时,减少线程等待subCondition.await();}String str lists.get(0);lists.remove(0);System.out.println(The Token Banana is [ str ]);System.out.println(The Current Thread is Thread.currentThread().getName());System.out.println();num--;addCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}} 转载于:https://www.cnblogs.com/liufei1983/p/8120395.html