建设部指定招标网站,设计网站开发方案流程,国家排污许可网站台账怎么做,seo是什么职位如果有兴趣了解更多相关内容#xff0c;欢迎来我的个人网站看看#xff1a;耶瞳空间
一#xff1a;基本介绍
从Java 5开始#xff0c;引入了一个高级的处理并发的java.util.concurrent包#xff0c;它提供了大量更高级的并发功能#xff0c;能大大简化多线程程序的编写…如果有兴趣了解更多相关内容欢迎来我的个人网站看看耶瞳空间
一基本介绍
从Java 5开始引入了一个高级的处理并发的java.util.concurrent包它提供了大量更高级的并发功能能大大简化多线程程序的编写。我们知道Java语言直接提供了synchronized关键字用于加锁但这种锁一是很重二是获取时必须一直等待没有额外的尝试机制。而java.util.concurrent.locks包提供的ReentrantLock用于替代synchronized加锁。
Lock是Java并发编程中很重要的一个接口它要比synchronized关键字更能直译锁的概念Lock需要手动加锁和手动解锁一般通过lock.lock()方法来进行加锁通过lock.unlock()方法进行解锁。一般会在finally块中写unlock( )以防死锁。而ReentrantLock实现了Lock接口。
ReentrantLock是一个可重入的互斥锁又被称为“独占锁”。可重入表示ReentrantLock锁可以被同一个线程多次获取而不会出现死锁。ReentraantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的。在“公平锁”的机制下线程依次排队获取锁而“非公平锁”在锁是可获取状态时不管自己是不是在队列的开头都会获取锁。
ReentrantLock和synchronized比较
synchronized是Java语言层面提供的语法而ReentrantLock是Java代码实现的锁。synchronized是独占锁加锁和解锁的过程自动进行易于操作但不够灵活。ReentrantLock也是独占锁加锁和解锁的过程需要手动进行不易操作但非常灵活。synchronized不可响应中断一个线程获取不到锁就一直等着ReentrantLock可以响应中断。
基本使用示例
public class Counter {private final Lock lock new ReentrantLock();private int count;public void add(int n) {lock.lock();try {count n;} finally {lock.unlock();}}
}二可重入
可重入是指同一个线程如果首次获得了这把锁那么因为它是这把锁的拥有者因此有权利再次获取这把锁。如果是不可重入锁那么第二次获得锁时自己也会被锁挡住
示例代码如下
public class Demo {static Lock lock new ReentrantLock();public static void main(String[] args) {method1();}public static void method1() {lock.lock();try {System.out.println(execute method1);method2();} finally {lock.unlock();}}public static void method2() {lock.lock();try {System.out.println(execute method2);} finally {lock.unlock();}}
}三可打断
public class Demo {static Lock lock new ReentrantLock();public static void main(String[] args) {Thread t1 new Thread(() - {try {// 如果没有竞争那么此方法就会获取lock对象锁// 如果有竞争就会进入阻塞队列可以被其他线程用interrupt方法打断System.out.println(尝试获得锁);lock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();// 没有获得锁在等待时被打断了return;}try {System.out.println(获取到锁了);} finally {lock.unlock();}}, t1);lock.lock();t1.start();try {Thread.sleep(1);System.out.println(打断t1);t1.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}
}四锁超时
当tryLock方法里没有传入参数时默认立刻尝试获得锁
public class Demo {static Lock lock new ReentrantLock();public static void main(String[] args) {Thread t1 new Thread(() - {System.out.println(t1线程启动。。。。。。);if (!lock.tryLock()) {System.out.println(t1线程获取锁失败返回);return;}try {System.out.println(t1线程获得了锁);} finally {lock.unlock();}}, t1);lock.lock();System.out.println(主线程获得了锁);t1.start();try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(主线程释放锁);lock.unlock();}}
}但tryLock还有重载方法tryLock(long time, TimeUnit unit)该方法会等待时间内一直尝试获得锁
public class Demo {static Lock lock new ReentrantLock();public static void main(String[] args) {Thread t1 new Thread(() - {System.out.println(t1线程启动。。。。。。);try {if (!lock.tryLock(2, TimeUnit.SECONDS)) {System.out.println(t1线程获取锁失败返回);return;}} catch (InterruptedException e) {System.out.println(等待被打断);e.printStackTrace();return;}try {System.out.println(t1线程获得了锁);} finally {lock.unlock();}}, t1);lock.lock();System.out.println(主线程获得了锁);t1.start();try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(主线程释放锁);lock.unlock();}}
}五公平锁
公平锁与非公平锁
公平锁的实现就是谁等待时间最长谁就先获取锁非公平锁就是随机获取的过程谁运气好cpu时间片轮询到哪个线程哪个线程就能获取锁
ReentrantLock默认是不公平但可以根据需要自行设置是否公平。ReentrantLock构造方法源码如下 /*** 创建一个ReentrantLock实例* 该方法等同于调用ReentrantLock(false)*/public ReentrantLock() {sync new NonfairSync();}/*** 根据传入的公平策略创建ReentrantLock实例* param fair true为公平策略false为非公平策略*/public ReentrantLock(boolean fair) {sync fair ? new FairSync() : new NonfairSync();}ReentrantLock公平锁相对于非公平锁来说多线程并发情况下的系统吞吐量偏低因为需要排队等待。所以ReentrantLock公平锁适应于多线程并发不是很高、倾向于先来先到的应用场景。
六条件变量
ReentrantLock中的条件变量功能类似于普通synchronized的wait、notify我们可以使用ReentranLlock锁配合Condition对象上的await()和signal()或signalAll()方法来实现线程间协作。与synchronized的wait和notify不同之处在于ReentrantLock中的条件变量可以有多个可以实现更精细的控制线程。
在介绍方法的使用之前先来了解一下Condition是什么。可以把Condition看作是Object监视器的替代品。众所周知Object有wait()和notify()方法用于线程间的通信。并且这两个方法只能在synchronized同步块内才可以调用所有线程的等待和唤醒都需要关联到监视器对象的WaitSet集合。Condition同样可以实现上面的线程通信。不同点在于synchronized锁对象关联的监视器对象仅有一个所以等待队列也只有一个。而一个ReentrantLock可以有多个Condition这样可以根据不同的业务需求在使用同一个lock锁对象的基础上使用多个等待队列让不同性质的线程加入到不同的等待队列当中。
AQS当中Condition的实现类是ConditionObject它是AQS的内部类所以无法直接实例化。可以配合ReentrantLock来使用。ReentrantLock中有newCondition()的方法来实例化一个ConditionObject对象因此可以调用多次newCondition()方法来得到多个等待队列。
使用流程
await前需要获得锁await 执行后会释放锁进入conditionObject等待await的线程被唤醒(或打断、或超时)取重新竞争lock锁竞争lock锁成功后从await后继续执行
示例代码如下
Slf4j
public class Demo {private static ReentrantLock lock new ReentrantLock();// 等烟休息室static Condition cigaretteRoom lock.newCondition();// 等外卖休息室static Condition eattingRoom lock.newCondition();static boolean hasCigarette false;static boolean hasTakeout false;public static void main(String[] args) throws InterruptedException {// 小南new Thread(() - {lock.lock();try {log.debug([{}], hasCigarette);while (!hasCigarette) {log.debug(没烟先歇会);try {cigaretteRoom.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug(有烟没[{}], hasCigarette);if (hasCigarette) {log.debug(可以开始干活了);}} finally {lock.unlock();}}, 小南).start();// 小女等外卖new Thread(() - {lock.lock();try {log.debug(外卖送到没[{}], hasTakeout);while (!hasTakeout) {log.debug(没外卖先歇会);try {eattingRoom.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug(外卖送到没[{}], hasTakeout);if (hasTakeout) {log.debug(可以开始干活了);} else {log.debug(没干成活...);}} finally {lock.unlock();}}, 小女).start();// 送烟的来了Thread.sleep(1000);new Thread(() - {lock.lock();try {hasCigarette true;cigaretteRoom.signal();} finally {lock.unlock();}}, 送烟的).start();// 送外卖的来了Thread.sleep(1000);new Thread(() - {lock.lock();try {hasTakeout true;eattingRoom.signal();} finally {lock.unlock();}}, 送外卖的).start();}
}