Java的可重入锁

1.可重入锁Lock

锁主要是为了保护临界区资源,防止由于并发执行而引起的数据异常。而synchronized关键字就是一种最简单的控制方法。经过jdk1.6对synchronized的优化,Lock和synchronized的性能相差并不多。 那么为什么还需要Lock,这当然有它的用处,
先看一个示例,锁的普通情况的使用:

import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockDemo implements Runnable {static int i = 0; //声明为静态变量,否则无法直接在main方法中调用ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {for (int j = 0; j < 10000; j++) {lock.lock(); //进行同步控制try {++i;} finally {lock.unlock(); //加锁部分写进try finally语句中,保证锁一定会被释放掉}}}public static void main(String[] args) {ReentrantLockDemo lockDemo = new ReentrantLockDemo();Thread t1 = new Thread(lockDemo);Thread t2 = new Thread(lockDemo);t1.start();t2.start();try {t1.join(); //等待t1线程和t2线程执行完毕t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i);}
}

Lock额外提供可几个以下的功能:
1)可重入
之所以把Lock称作可重入锁,是因为这把锁是可以反复进入的,当然这里反复进入仅仅局限于一个线程。上述代码的加锁部分,也可以加两把锁,如下:

lock.lock();
lock.lock();
try {++i;
} finally {lock.unlock();lock.unlock();
}

注意:如果同一个线程多次获得锁,那么也必须释放相同次数的锁;如果释放次数多,那么会得到一个java.lang.IllegalMonitorStateException异常;如果释放次数少,那么其它线程将不能进入临界区。
2)中断响应
对于synchronized来说,如果一个线程在等待锁,那么结果只有两种情况,要么它获得锁继续执行,要么就等待。而使用重入锁,那么锁可以被中断,即在等待过程中,程序可以根据需要取消对锁的请求。

import java.util.concurrent.locks.ReentrantLock;public class IntLock implements Runnable{ReentrantLock lock1 = new ReentrantLock();ReentrantLock lock2 = new ReentrantLock();int lock;public IntLock(int lock) {this.lock = lock;}@Overridepublic void run() {//这里的if else主要是为了模拟死锁操作,这样可以看到通过调用中断方法,一个线程被中断,而另一个线程正常执行try {if (lock == 1){lock1.lockInterruptibly(); //调用这个方法加锁,同时可以响应中断Thread.sleep(500);lock2.lockInterruptibly();System.out.println(Thread.currentThread().getId() + ": 完成");}else {lock2.lockInterruptibly();Thread.sleep(500);lock1.lockInterruptibly();System.out.println(Thread.currentThread().getId() + ": 完成");}} catch (InterruptedException e) {e.printStackTrace();}finally {if(lock1.isHeldByCurrentThread()) //如果这把锁被当前线程持有,那么就释放这把锁lock1.unlock();if (lock2.isHeldByCurrentThread())lock2.unlock();System.out.println(Thread.currentThread().getId() + ": 线程退出!");}}public static void main(String[] args) {IntLock intLock1 = new IntLock(1);IntLock intLock2 = new IntLock(2);Thread t1 = new Thread(intLock1);Thread t2 = new Thread(intLock2);t1.start();t2.start();t1.interrupt(); //中断线程1}
}

3)锁申请等待限时

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class TryLockDemo implements Runnable{ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {try {if(lock.tryLock(5, TimeUnit.SECONDS)){ //锁申请等待限时,等待5秒钟Thread.sleep(6000);System.out.println(Thread.currentThread().getId() + "complete!");}else {System.out.println(Thread.currentThread().getId() + "get lock failed");}} catch (InterruptedException e) {e.printStackTrace();} finally {if(lock.isHeldByCurrentThread()) //如果当前线程持有该锁,则释放锁lock.unlock();}}public static void main(String[] args) {TryLockDemo tryLockDemo = new TryLockDemo();Thread t1 = new Thread(tryLockDemo);Thread t2 = new Thread(tryLockDemo);t1.start();t2.start();}
}

tryLock()也可以不带参数直接运行,在这种情况下,如果申请不成功,则直接返回false,不会等待。
4)总结
public void lock():获得锁,如果锁已经被占用,则等待;
public void lockInterruptibly():获得锁,但优先响应中断;
public boolean tryLock():尝试获得锁,如果成功返回true,继续执行;如果失败,返回false,不等待;
boolean tryLock(long timeout, TimeUnit unit):锁申请等待限时;
public void unlock():释放锁;

2.线程通信 (Condition)

Condition提供了一下几个方法:

void await() throws InterruptedException;
void awaitUninterruptibly();
boolean await(long time, TimeUnit unit) throws InterruptedException;
void signal();
void signalAll();

其和Object.wait()、Object.notify()方法作用类似;
await()方法使当前线程等待,同时释放锁;在其它线程中调用signal()方法或者signalAll()方法,线程会被唤醒,获得锁继续执行。当线程被中断时,也能跳出等待;
awaitUninterruptibly()作用和await()方法类似,但它不响应中断;
signal()方法用于唤醒线程。
示例如下:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ConditionDemo implements Runnable {private static Lock lock = new ReentrantLock(); //把变量声明为静态变量,这样可以直接在main方法中使用private static Condition condition =  lock.newCondition();@Overridepublic void run() {try {lock.lock();condition.await();System.out.println("执行完毕");} catch (InterruptedException e) {e.printStackTrace();}finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {ConditionDemo conditionDemo = new ConditionDemo();Thread t1 = new Thread(conditionDemo);t1.start();Thread.sleep(2000);//通知线程t1继续执行lock.lock(); //和Object的notify方法同理,这里也需要先获得重入锁,才能执行signal()方法condition.signal();lock.unlock(); //在唤醒线程之后,需要释放锁;如果省略这行代码,那么就算t1被唤醒,但由于它无法获得重入锁,//因而就无法继续执行。}
}

一旦线程被唤醒,它会重新尝试获得与其绑定的重入锁,如果成功获取就继续执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/549117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创建oracle 数据库表空间,角色,用户的sql语句

创建oracle 数据库表空间&#xff0c;角色&#xff0c;用户的sql语句 1.创建角色 CREATE ROLE "QIUDINGROLE" NOT IDENTIFIED; GRANT "CONNECT" TO "QIUDINGROLE";GRANT "DBA" TO "QIUDINGROLE";GRANT "RESOURCE"…

JBoss5开发web service常见问题

最近在研究EJB3&#xff0c;在使用EJB3的Web service的时候遇到了不少棘手的问题&#xff0c;现在总结常见问题与大家分享&#xff0c;希望您能少浪费些时间去漫天地搜解决方案&#xff0c;具体见下&#xff1a; 1.服务器端错误信息&#xff1a;jboss5 java.lang.NoClassDefFou…

面试题:谈谈你对TCP的认识

一 TCP 1. 简介 首先&#xff0c;TCP是一个传输层协议&#xff0c;提供进程到进程之间的可靠性数据传输服务&#xff0c;还提供流量控制和差错控制等机制。 其次&#xff0c;TCP是面向连接的&#xff0c;其通信模式是全双工的&#xff1b;面向连接是指&#xff1a; 在发送数…

WCF Data Services 基础

把最近使用的WCF Data Service和WCF RIA Service的使用例子发布在站点http://dskit.codeplex.com &#xff0c; 本系列文章就把WCF Data Service和WCF RIA Service涉及的主要方面描述一下&#xff0c;希望通过这些内容&#xff0c;可以比较顺畅的把这些框架使用起来&#xff0c…

面试题:MySQL的innodb和myisam

一 Innodb 1. 简介 索引是一种排好序的用于快速查找的数据结构。 **根据官网手册InnoDB支持B-tree索引、聚簇索引(Clustered indexes)、全文索引(Full-text search indexes)、不支持hash索引&#xff08;InnoDB在内部利用哈希索引来实现其自适应哈希索引功能&#xff09…

用Markup Validation Service进行网页的W3C标准语法验证(c#)

W3C提供免费的Markup Validation Service&#xff0c;这是一个可以验证Html/XHtml文档的语法规范的公共服务。在某种程度上&#xff0c;有了它&#xff0c;我们再也不用为不能全面及时检测众多浏览器和五花八门的js/css不兼容性而痛不欲生了。^-^。 使用方法很简单&#xff0c;…

为什么MySQL索引更适合B+树而不是二叉树、B树

一 数据库为什么使用B树 1. 与二叉树相比 二叉树相比于顺序查找的确减少了查找次数&#xff0c;但是在最坏情况下&#xff0c;二叉树有可能退化为顺序查找。而且就二叉树本身来说&#xff0c;当数据库的数据量特别大时&#xff0c;其层数也将特别大。二叉树的高度一般是log_2…

SIP 電話

下載转载于:https://www.cnblogs.com/kevinsun/archive/2010/10/18/1854021.html

【数据安全案例】交警计算机系统再遭***,交通违法记录随意删除

根据新浪报道&#xff0c;据新华社10月14日电 利用当网管的机会&#xff0c;破解密码&#xff0c;非法进入交警计算机系统为他人删除车辆交通违法记录牟利。辽宁省鞍山市铁西区检察院透露&#xff0c;当地某公司员工程尚军因涉嫌破坏计算机信息系统罪&#xff0c;已于10月初被依…

将Java应用程序本地编译为EXE的几种方法

将Java应用程序本地编译为EXE的几种方法(推荐使用JOVE和JET)  1. 从[url]www.towerj.com[/url]获得一个TowerJ编译器&#xff0c;该编译器可以将你的CLASS文件  编译成EXE文件。  2. 利用微软的SDK-Java 4.0所提供的jexegen.exe创建EXE文件&#xff0c;这个软件可以  从微软…

MDOP套装之app-v安装使用及功能说明

最近尝试了瑞友天翼的虚拟化产品&#xff0c;感觉还不错&#xff0c;正好手上又下载了个mdop套装&#xff0c;顺手做了个app-v实验&#xff0c;其他实验教程后期继续推出。 一、服务端的安装 二、排序工具的安装 三、客户端的安装 四、使用排序工具虚拟化一个程序 五、发布虚…

奇虎360大战腾讯QQ 高潮迭起用户受伤

原文地址&#xff1a;奇虎360大战腾讯QQ 高潮迭起用户受伤 虽然我也是不可避免的QQ用户&#xff0c;但是自从360开始揭露腾讯QQ涉及扫描用户隐私引发的这场高潮迭起的比拼谁更淫荡谁更无耻的战争中&#xff0c;我心中的一碗水一直端的很平&#xff0c;就像对待小泽和空姐的作品…

容器技术之Dockerk8s知识笔记

本文带你快速了解Kubernetes与Docker 让你对容器与虚拟机的区别、Docker与k8s有一个快速的了解 目录 演变史容器与虚拟机的区别K8S与Docker概念DockerK8S演变史 传统部署时代&#xff1a; 早期&#xff0c;将单一的应用服务运行在物理服务器上&#xff0c;无法给服务器的应用…

容器技术之kubectl常用命令

kubectl用于运行Kubernetes集群命令的管理工具。本文概述涵盖了kubectl语法&#xff0c;对命令操作的描述&#xff0c;并列举了常用命令。 Kubectl命令详细列表请查看&#xff1a;Kubernetes kubectl 命令表 语法 $ kubectl [command] [TYPE] [NAME] [flags] command&#x…

Container.ItemIndex 获取reapeater行号

<div class"<%# (Container.ItemIndex)4?"class3":"class4"%>"></div>取到第五行的行号&#xff0c;用一个三元运算符来判断div的样式。 图中container.itemindex(container.ItemIndex-5)是不对的&#xff0c;最上面的代码才…

容器技术之快速了解K8S各抽象资源及组件架构

带你快速了解Kubernetes主要概念和组件架构。 Kubernetes的组件和架构比较多&#xff0c;功能也比较多。 如果详细探讨&#xff0c;每个Kubernetes组件都可以单独写篇博客详细讲解。 我们这里是快速了解&#xff0c;就写的相对比较简单一些。 主要是针对不熟悉Kubernetes的…

《活法》中一个故事--令托尔斯泰也折服的人性寓言

某个深秋的日子里&#xff0c;在枯树残枝任萧瑟秋风吹袭的景色中&#xff0c;有位旅人正在赶路回家&#xff0c;突然间&#xff0c;他发现脚边有一堆白白的东西&#xff0c;定睛一看&#xff0c;竟然是人骨。这种地方怎么会有人骨头?他觉得浑身不对劲却又想不透&#xff0c;可…

Python可视化神器之pyecharts

目录 概述安装参数实例 柱状图-Bar饼图-Pie折线图-Line散点图-scatter3D 柱状图-Bar3D仪表盘-Gauge雷达图-Radar词云图-WordCloud地理坐标系-Geo地图-Map概述 Pyecharts是一款将python与echarts结合的强大的数据可视化工具。使用 pyecharts 可以生成独立的网页&#xff0c;也…

我就不文明了

不是 我就的 我咋就这么笨呢 妈了个逼的 本来就没有基础 本来就英文不好 本来就找不到入门的方向 怎们所有人 都在打击我 怎么所有人 都说我不可能成功 我他吗的就不信了 我就学 我就盲目的寻找 我就不信 我实现不了自己的梦转载于:https://blog.51cto.com/100000372/422302

计算机基础之IP地址、子网掩码、网络号、主机号、主机数、网络地址、广播地址

相关概念&#xff1a;IP地址、子网掩码、网络号、主机号、主机数、网络地址、广播地址 IP地址&#xff1a;由4字节/32位表示&#xff0c;通常用点分十进制表示法&#xff0c;例如192.168.1.1&#xff0c;对应的二进制就是11000000 10101000 00000001 00000001 IP地址通常有下…