- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
在JDK5中新增了Lock锁接口,有ReentrantLock实现类等。ReentrantLock锁称为可重入锁,它的功能要比synchronized多。
锁的可重入性是指,当一个线程获得一个对象锁后,再次请求该对象锁时,可以再次获得该对象的锁。
以下代码可以顺利运行下去,代表synchronized里面的锁是具有可重入性的:
package lock.reentrant;
public class Test01 {
public synchronized void sm1() {
System.out.println("同步方法1");
sm2();
}
public synchronized void sm2() {
System.out.println("同步方法2");
sm3();
}
public synchronized void sm3() {;
System.out.println("同步方法3");
}
public static void main(String[] args) {
Test01 obj = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
obj.sm1();
}
}).start();
}
}
ReentrantLock的基本使用:
package lock.reentrant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用lock锁同步不同方法中的同步代码块
*
* 只要使用了同一个Lock,不管在哪里的代码都可以进行同步
*/
public class Test03 {
static Lock lock = new ReentrantLock(); //定义锁对象
public static void sm1() {
//经常在try中获得Lock锁,在finally()代码块中释放锁
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "--method1--" + System.currentTimeMillis());
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "--method1--" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void sm2() {
//经常在try中获得Lock锁,在finally()代码块中释放锁
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "--method2--" + System.currentTimeMillis());
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + "--method2--" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
sm1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
sm2();
}
}).start();
}
}
一般将lock.lock()写在try中,lock.unlock()写在finally中。
不管在哪里的代码,只要使用了同一个Lock,都可以进行线程同步。
lockInterruptibly()方法:
如果在获取锁的过程中,线程的中断标志位为true,则获取锁失败,且立即报InterruptedException异常,并将中断标志位的值置为false。
对于synchronized内部锁来说,如果一个线程在等待锁,只有两个结果。要么线程获得锁继续执行,要么就保持。
对于Reentrant Lock可重入锁来说,提供了另外一种可能,在等待锁的过程中,程序可以根据需要取消对锁的请求。
lockInterruptibly()方法解决死锁问题:
package lock.reentrant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test06 {
static class IntLock implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
int lockNum = 0; //定义整数变量,决定使用哪个锁
public IntLock(int lockNum) {
this.lockNum = lockNum;
}
@Override
public void run() {
try {
if(lockNum % 2 == 1) {
lock1.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + "获得了锁1,还需要获得锁2");
TimeUnit.SECONDS.sleep(1);
lock2.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + "同时获得了锁1和锁2");
} else { //偶数
lock2.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + "获得了锁2,还需要获得锁1");
TimeUnit.SECONDS.sleep(1);
lock1.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + "同时获得了锁1和锁2");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(lock1.isHeldByCurrentThread()){
lock1.unlock();
System.out.println(Thread.currentThread().getName() + "释放了lock1");
}
if(lock2.isHeldByCurrentThread()) {
lock2.unlock();
System.out.println(Thread.currentThread().getName() + "释放了lock2");
}
System.out.println(Thread.currentThread().getName() + "线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
IntLock intLock1 = new IntLock(1);
IntLock intLock2 = new IntLock(2);
Thread t1 = new Thread(intLock1);
Thread t2 = new Thread(intLock2);
t1.start();
t2.start();
//睡眠3s,如果程序还没结束,中断一个线程,让其放弃申请锁,并释放自己占有的锁
TimeUnit.SECONDS.sleep(3);
if(t1.isAlive()) t1.interrupt();
// if(t2.isAlive()) t2.interrupt();
}
}
}
tryLock(Long time, TimeUnit):限时等待,在给定时间内如果能获得该锁就获得,得不到就放弃申请。
tryLock():调用时如果该锁能获得就获得,否则就放弃申请。
代码示例:
package lock.reentrant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class Test08 {
static class TimeLock implements Runnable {
private static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
if(lock.tryLock(3, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + "获得锁,执行耗时任务");
TimeUnit.SECONDS.sleep(5);
} else { //没有获得锁
System.out.println(Thread.currentThread().getName() + "没有获得锁");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println(Thread.currentThread().getName() + "释放了锁");
}
}
}
}
public static void main(String[] args) {
TimeLock timeLock1 = new TimeLock();
TimeLock timeLock2 = new TimeLock();
Thread t1 = new Thread(timeLock1);
Thread t2 = new Thread(timeLock2);
t1.start();
t2.start();
}
}
tryLock()避免死锁:
package lock.reentrant;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用tryLock()避免死锁
*/
public class Test10 {
static class IntLock implements Runnable {
private static ReentrantLock lock1 = new ReentrantLock();
private static ReentrantLock lock2 = new ReentrantLock();
int lockNum = 0;
public IntLock(int lockNum) {
this.lockNum = lockNum;
}
@Override
public void run() {
try {
if(lockNum % 2 == 0) {
if(lock1.tryLock()) {
System.out.println(Thread.currentThread().getName() + "获取锁1,尝试获取锁2");
Thread.sleep(1000);
}
if(lock2.tryLock()) {
System.out.println(Thread.currentThread().getName() + "获取锁2,同时获取了锁1和锁2");
}
} else {
if(lock2.tryLock()) {
System.out.println(Thread.currentThread().getName() + "获取锁2,尝试获取锁1");
Thread.sleep(1000);
}
if(lock1.tryLock()) {
System.out.println(Thread.currentThread().getName() + "获取锁1,同时获取了锁1和锁2");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(lock1.isHeldByCurrentThread()) {
lock1.unlock();
System.out.println(Thread.currentThread().getName() + "释放了锁1");
} else {
lock2.unlock();
System.out.println(Thread.currentThread().getName() + "释放了锁2");
}
}
}
}
public static void main(String[] args) {
IntLock intLock1 = new IntLock(1);
IntLock intLock2 = new IntLock(2);
new Thread(intLock1).start();
new Thread(intLock2).start();
}
}
newCondition()方法:
synchronized与wait()、notify()这两个方法一起使用可以实现等待/通知模式,Lock锁的newCondition()方法返回Condition对象,也可以实现等待/通知模式
使用notify()通知后,JVM会随机唤醒某个等待的线程,使用Condition类可以进行选择性地通知某和线程。Condition比较常用的两个方法:await()、singal()。注意,在调用这两个方法前,需要线程持有相关的Lock锁。调用await()后,线程会释放这个锁,调用signal()后,会从当前Condition对象的等待序列中唤醒一个线程。
公平锁与非公平锁:
大多数情况下,锁是非公平的,也就是说,当好几个线程在申请锁A时,可能某几个线程申请成功的概率大于其他线程。
公平锁:会按照时间先后顺序分配锁,保证先到先得,不会让线程饥饿。
synchronized这个内部锁是非公平的,ReentrantLock在定义是可以通过其构造方法让其变成公平锁,ReentrantLock(boolean fair)。
如果是非公平锁,系统会倾向于让一个已经获得了锁的线程继续获得锁,因为这样比较高效;如果是公平锁,系统会选择等待时间最长的那个线程获得锁。公平锁需要维护一个有序队列,所以性能不高。如果不是特别的需求,一般不使用公平锁。
package lock.method;
import java.util.concurrent.locks.ReentrantLock;
/**
* 公平锁和非公平锁
*/
public class Test01 {
// private static ReentrantLock lock = new ReentrantLock(); //默认是非公平锁
private static ReentrantLock lock = new ReentrantLock(true); //定义成公平锁
public static void main(String[] args) {
for(int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得了锁");
} finally {
lock.unlock();
}
}
}
}, "Thread" + i).start();
}
}
}
ReentrantLock的几个常用的方法:
1、 getHoldCount():返回当前线程调用lock()方法的次数;
package lock.method;
import java.util.concurrent.locks.ReentrantLock;
public class Test02 {
private static ReentrantLock lock = new ReentrantLock();
public static void m1() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "持有了:" + lock.getHoldCount());
//引文ReentrantLock是可重入锁,所以可以继续在m2()方法中继续获得锁
m2();
} finally {
lock.unlock();
}
}
public static void m2() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "持有了:" + lock.getHoldCount());
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
m1();
}
}
2、 getQueueLength():返回正等待获得此锁的线程预估数;
package lock.method;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* getQueueLength() 返回获得锁的线程预估数
*/
public class Test03 {
private static ReentrantLock lock = new ReentrantLock();
private static class SubThread extends Thread {
@Override
public void run() {
try {
lock.lock();
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName() + ":" + lock.getQueueLength());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
new SubThread().start();
}
}
}
3、 getWaitQueueLength(Conditioncondition):返回在condition队列上等待的线程预估数;
4、 hasQueuedThread(Threadthread):查询某线程是否在等待获得该锁;
5、 hasQueuedThreads():查询是否有其他线程在等待获得该锁;
6、 hasWaiters(Conditioncondition):查询在该condition队列上是否有线程在等待;
7、 isHeldByCurrentThread():判断锁是否被当前线程锁持有;
8、 isLocked():判断锁是否被任何一个线程锁持有;
我的Angular-Component位于一个flexbox(id =“log”)中。可以显示或隐藏flexbox。 我的组件内部有一个可滚动区域,用于显示日志消息。 (id =“message-li
我真的很困惑 有一个 phpinfo() 输出: MySQL 支持 启用 客户端 API 版本 5.5.40 MYSQL_MODULE_TYPE 外部 phpMyAdmin 显示: 服务器类型:Mar
我正在研究这个 fiddle : http://jsfiddle.net/cED6c/7/我想让按钮文本在单击时发生变化,我尝试使用以下代码: 但是,它不起作用。我应该如何实现这个?任何帮助都会很棒
我应该在“dogs_cats”中保存表“dogs”和“cats”各自的ID,当看到数据时显示狗和猫的名字。 我有这三个表: CREATE TABLE IF NOT EXISTS cats ( id
我有一个字符串返回到我的 View 之一,如下所示: $text = 'Lorem ipsum dolor ' 我正在尝试用 Blade 显示它: {{$text}} 但是,输出是原始字符串而不是渲染
我无法让我的链接(由图像表示,位于页面左侧)真正有效地显示一个 div(包含一个句子,位于中间)/单击链接时隐藏。 这是我的代码: Practice
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
最初我使用 Listview 来显示 oracle 结果,但是最近我不得不切换到 datagridview 来处理比 Listview 允许的更多的结果。然而,自从切换到数据网格后,我得到的结果越来越
我一直在尝试插入一个 Unicode 字符 ∇ 或 ▽,所以它显示在 Apache FOP 生成的 PDF 中。 这是我到目前为止所做的: 根据这个基本帮助 Apache XSL-FO Input,您
我正在使用 node v0.12.7 编写一个 nodeJS 应用程序。 我正在使用 pm2 v0.14.7 运行我的 nodejs 应用程序。 我的应用程序似乎有内存泄漏,因为它从我启动时的大约 1
好的,所以我有一些 jQuery 代码,如果从下拉菜单中选择了带有前缀 Blue 的项目,它会显示一个输入框。 代码: $(function() { $('#text1').hide();
当我试图检查 Chrome 中的 html 元素时,它显示的是 LESS 文件,而 Firefox 显示的是 CSS 文件。 (我正在使用 Bootstrap 框架) 如何在 Chrome 中查看 c
我是 Microsoft Bot Framework 的新手,我正在通过 youtube 视频 https://youtu.be/ynG6Muox81o 学习它并在 Ubuntu 上使用 python
我正在尝试转换从 mssql 生成的文件到 utf-8。当我打开他的输出 mssql在 Windows Server 2003 中使用 notepad++ 将文件识别为 UCS-2LE我使用 file
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我正在尝试执行单击以打开/关闭一个 div 的功能。 这是基本的,但是,点击只显示 div,当我点击“关闭”时,没有任何反应。 $(".inscricao-email").click(function
假设我有 2 张卡片,屏幕上一次显示一张。我有一个按钮可以用其他卡片替换当前卡片。现在假设卡 1 上有一些数据,卡 2 上有一些数据,我不想破坏它们每个上的数据,或者我不想再次重建它们中的任何一个。
我正在使用 Eloquent Javascript 学习 Javascript。 我在 Firefox 控制台上编写了以下代码,但它返回:“ReferenceError:show() 未定义”为什么?
我正在使用 Symfony2 开发一个 web 项目,我使用 Sonata Admin 作为管理面板,一切正常,但我想要做的是,在 Sonata Admin 的仪表板菜单上,我需要显示隐藏一些菜单取决
我试图显示一个div,具体取决于从下拉列表中选择的内容。例如,如果用户从列表中选择“现金”显示现金div或用户从列表中选择“检查”显示现金div 我整理了样本,但样本不完整,需要接线 http://j
我是一名优秀的程序员,十分优秀!