java 同步 lock_关于java:同步是否像Lock.lock()一样驻留并发线程?

当我们调用lock.lock()或尝试输入synchronized块时,如果其他某个线程已经获得了该锁,则我们的线程将阻塞。 现在我的问题是,当我们查看lock.lock()的实现时,它会将获取锁委托给AQS,而AQS实际将当前线程驻留在该线程中(因此调度程序无法对其进行进一步调度)。

synchronized阻塞是否也是如此?

我什至认为我的线程状态也不同。 例如,如果我的线程在synchronized块上被阻塞,则它将是BLOCKING,而如果我调用了

lock.lock(),则为WAITING。 我对吗?

我关心的是以下两种锁定策略在Thread.status方面与通过停车而不是忙于等待来提高性能之间的区别

ReentrantLock.lock();

synchronize { /*some code */ }

抱歉,我从自动翻译器回复。 我认为您应该附加示例代码,这将帮助我们帮助您分析问题。 一般在使用同步时,可以不必锁定。 锁 ()。 一般来说,足够同步。

调用lock或lockInterruptibly会将线程置于WAITING状态:

Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

Object.wait with no timeout

Thread.join with no timeout

LockSupport.park

以下代码启动四个线程,前两个(A,B)运行相同的代码,并通过lock方法锁定某些监视器。 另外两个(C,D)也运行相同的代码,但是它们通过lockInterruptibly方法锁定了另一个监视器:

public static synchronized void dumpThreadState(List threads) {

System.out.println("thread state dump start");

for (Thread t: threads) {

System.out.println(t.getName()+""+t.getState());

}

System.out.println("thread state dump end\

");

}

public static void main(String[] args) throws InterruptedException {

final Lock lock = new ReentrantLock();

final Lock anotherLock = new ReentrantLock();

List threads = new LinkedList();

Runnable first = new Runnable() {

@Override

public void run() {

try {

lock.lock();

}

catch (Exception ex) {

System.out.println(Thread.currentThread().getName()+" processing exception"+ex.getClass().getSimpleName());

}

while (true);

}

} ;

Runnable second = new Runnable() {

@Override

public void run() {

try {

anotherLock.lockInterruptibly();

}

catch (InterruptedException ex) {

System.out.println(Thread.currentThread().getName()+" was interrupted");

}

while (true);

}

};

threads.add(new Thread(first,"A"));

threads.add(new Thread(first,"B"));

threads.add(new Thread(second,"C"));

threads.add(new Thread(second,"D"));

dumpThreadState(threads);

for (Thread t: threads) {

t.start();

}

Thread.currentThread().sleep(100);

dumpThreadState(threads);

System.out.println("interrupting" + threads.get(1).getName());

threads.get(1).interrupt();

dumpThreadState(threads);

System.out.println("interrupting" + threads.get(3).getName());

threads.get(3).interrupt();

Thread.currentThread().sleep(100);

dumpThreadState(threads);

for (Thread t: threads) {

t.join();

}

}

它输出:

thread state dump start

A NEW

B NEW

C NEW

D NEW

thread state dump end

thread state dump start

A RUNNABLE

B WAITING

C RUNNABLE

D WAITING

thread state dump end

interrupting B

thread state dump start

A RUNNABLE

B WAITING

C RUNNABLE

D WAITING

thread state dump end

interrupting D

D was interrupted

thread state dump start

A RUNNABLE

B WAITING

C RUNNABLE

D RUNNABLE

thread state dump end

可以看出,通过lock方法锁定的线程不能被中断,而通过lockInterruptibly锁定的线程可以被中断。

在另一个示例中,启动了三个线程,前两个(A,B)运行相同的代码,并通过synchronized块锁定在同一监视器上。 第三个线程锁定在另一个监视器上,但通过wait方法等待:

public static void main(String[] args) throws InterruptedException {

final Object lock = new Object();

final Object anotherLock = new Object();

List threads = new LinkedList();

Runnable first = new Runnable() {

@Override

public void run() {

synchronized(lock) {

while (true);

}

}

} ;

Runnable second = new Runnable() {

@Override

public void run() {

synchronized(anotherLock) {

try {

anotherLock.wait();

}

catch (InterruptedException ex) {

ex.printStackTrace();

}

}

}

};

threads.add(new Thread(first,"A"));

threads.add(new Thread(first,"B"));

threads.add(new Thread(second,"C"));

dumpThreadState(threads);

for (Thread t: threads) {

t.start();

}

Thread.currentThread().sleep(100);

dumpThreadState(threads);

for (Thread t: threads) {

t.join();

}

}

它输出:

thread state dump start

A NEW

B NEW

C NEW

thread state dump end

thread state dump start

A RUNNABLE

B BLOCKED

C WAITING

thread state dump end

线程C以WAITING状态结束,而线程B以BLOCKING状态结束:

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait.

编辑:

这是一个非常好的线程状态的UML图。

阻止-在资源上被阻止,无法被中断

等待-在资源上被阻止,但可以被中断,通知或取消停放。

如您所见,Waiting更好地控制了另一个处理程序。例如如果两个线程死锁,则可以通过中断来中断lock()。使用同步的两个线程时,您将陷入困境。

同步vs锁定的行为非常相似,确切的细节在主要版本之间有所不同。

我的建议是使用

同步以获取需要线程安全但锁争用非常低的简单代码。

在已确定有锁争用的地方使用Lock,或者需要其他功能,例如tryLock。

如果你这样做

final Lock lock = new ReentrantLock();

lock.lock();

Thread t = new Thread(new Runnable() {

@Override

public void run() {

try {

lock.lockInterruptibly();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

t.start();

Thread.sleep(100);

System.out.println(t +" is" + t.getState());

lock.unlock();

版画

Thread[Thread-0,5,main] is WAITING

Thread.State状态

等待线程的线程状态。由于调用以下方法之一,线程处于等待状态:

Object.wait没有超时

Thread.join没有超时

LockSupport.park

处于等待状态的线程正在等待另一个线程执行特定操作。例如,一个在对象上调用Object.wait()的线程正在等待另一个线程在该对象上调用Object.notify()或Object.notifyAll()。名为Thread.join()的线程正在等待指定的线程终止。

谢谢@Peter Lawrey,当线程被lock.lock()阻塞时,线程的状态如何?

好的一点是,lock()将被阻塞,而lockInterruptably()将被等待,因为它可以被中断。

@PeterLawrey调用锁也会使线程也处于等待状态

驻留线程和同步阻塞是非常不同的。尝试输入同步块时,您将明确尝试在对象实例上获取监视器。如果无法获取监视器,则线程将进入"阻塞"状态,直到监视器可用为止。停放与Object.wait()方法更相似,因为代码知道在其他条件变为真之前它不能继续。阻止在这里是没有意义的,因为这将是徒劳的,因为我目前继续的条件是正确的。此时,我进入WAITING或TIMED_WAITING状态(取决于等待的发出方式),直到被通知(通过类似notify(),notifyAll()或unpark()的通知)为止。一旦我的条件变为真,我就进入等待状态,然后可能会尝试获取监视器并在需要时进入阻塞状态。如果我得到显示器,则进入"运行"并继续快乐地前进

因此,等待实际上就是知道我无法做某事,并在认为可以的情况下让其他线程通知我。我醒来后可能导致阻塞。阻塞只是争夺对监视器的访问,而没有其他明确的先决条件。

在Lock实例上调用lock()时,调用线程实际上处于等待状态,并且没有阻塞。这样做的好处是可以中断此等待状态,这有助于避免死锁。对于类似Lock类的东西,您可以通过tryLock(),tryLock(long,TimeUnit),lock()和lockInterruptibly()来选择所需的等待行为。您可以指定诸如要等待多长时间以及是否可以通过调用哪种方法打扰您之类的事情。使用synchronized代码,您没有此类选项。您正在阻塞,并且被阻塞阻塞,直到某个线程放弃了您想要的监视器为止,如果从未中断,您将陷入僵局。这就是为什么从Java 5和concurrent包开始,您应该避免使用synchronized关键字,而是尝试使用Lock和Condition之类的东西实现类似的语义。

谢谢@ cmbaxter,实际上我想问的是,当它调用Reentrantlock.lock()时,线程实际上进入了停车状态。 这就是为什么我的问题在ReentrantLock.lock()中被阻止的原因实际上并未被阻止

是的,如果锁当前不可用,则调用lock会将调用线程置于WAITING状态。

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

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

相关文章

Idea项目中常见错误及笔记(Old)

1、Idea基础设置: File-->settings--> 1>修改字体:Font 2>修改编码格式:File Encodings(全部UTF-8,右下方复选框勾中--防止程序中的汉字转为ASCII码) 3>修改行号:Appearance:show line numbers show me…

java接口服务编排_GOKU API Gateway CE V3.1.0 发布:新增服务编排、配置版本管理等...

Goku API Gateway (中文名:悟空 API 网关)是一个基于 Golang 开发的微服务网关,能够实现高性能 HTTP API 转发、服务编排、多租户管理、API 访问权限控制等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界…

maxcompute 2.0复杂数据类型之array

2019独角兽企业重金招聘Python工程师标准>>> 1. 含义 类似于Java中的array。有序、可重复。 2. 场景 什么样的数据,适合使用array类型来存储呢?这里列举了几个我在开发中实际用到的场景。 2.1 标签类的数据 为什么说标签类数据适合使用array类…

java中匿名数组_Swagger UI:数组中的多个匿名对象

对象数组的定义如下:type: arrayitems:type: objectproperties:prop1:type: stringprop2:type: integer# etc.在您的示例中,响应包含具有属性 balanceDisplaySettings 的对象,并且此属性包含对象数组 . 这可以定义如下:paths:/Pat…

java ioutils 写入文件_文件输入输出流工具: IOUtils使用总结

序言以前写文件的复制很麻烦,需要各种输入流,然后读取line,输出到输出流...其实apache.commons.io里面提供了输入流输出流的常用工具方法,非常方便。下面就结合源码,看看IOUTils都有什么用处吧!常用的静态变…

权限组件(6):权限分配的角色管理

效果图: 为了方便开发,先把中间件注释掉,要不还要在角色-权限表中添加对应关系。又因为二级菜单和面包屑导航需要中间件的变量,所以要在layout.html里面把这两个也注释掉。setting.py# rbac.middlewares.rbac.RbacMiddleware layo…

java 面试700问_JAVA面试700问(一)

1、Java环境中的字节码是什么?由Java 编译器生成的一种代码。由JVM生成的一种代码。Java源文件(Java Source File)的别名。一种写在类的实例方法中的代码。答案:由Java 编译器生成的一种代码。2、什么是Java垃圾回收机制?操作系统周期性的删除…

02-Django基础知识

一、内容回顾 1、web应用程序 2、HTTP协议 a、http协议特性 b、http请求格式 c、http响应格式 3、wsgiref模块 4、Django下载与简单应用 a、Django简介(MTV) b、下载django命令 c、创建项目命令 d、创建app应用 e、启动项目   二、今日概要 1、路由层&…

java条码大小_java - ML Kit条形码扫描:无效的图像数据大小

我想在捕获的图像中检测条形码。我使用android的camera2捕获图像。此后,将检索图像的元数据并将图像保存到设备。元数据全部传递到下一个活动,该活动是应用程序尝试检测条形码的地方。下一个活动是从先前保存的文件创建一个byte []。接下来,使…

MongoDB数据库泄露8亿电邮地址;微软开源Windows计算器;Linux 5.0 Kernel发布丨Q新闻...

本周要闻:华为正式宣布起诉美国政府;360 首席安全官谭晓生宣布离职;阿里开源 Flutter 应用框架 Fish Redux;微软开源 Windows 计算器;Linux 5.0 Kernel 发布;电邮验证服务泄漏 8 亿电邮地址;Chr…

mysql 视图 分页_mysql查看所有存储过程,函数,视图,触发器,表,分页

查询数据库中的存储过程和函数方法一:select name from mysql.proc where db your_db_name and type PROCEDURE //存储过程select name from mysql.proc where db your_db_name and type FUNCTION //函数方法二:show procedure status; //存储过程sh…

postman里测试文件上传(MultipartFile)

1、后台方法: Override PostMapping("/importNumberSpaceData") public DataImportOutDTO importNumberSpaceData(MultipartFile file) throws Exception { return dataImportOutDTO; } 2、启用postman 1、POST方法; 2、Body-form-data,key为后…

java解析上的jar包里的pom_Maven引入本地Jar包并打包进War包中的方法

1.概述在平时的开发中,有一些Jar包因为种种原因,在Maven的中央仓库中没有收录,所以就要使用本地引入的方式加入进来。2. 拷贝至项目根目录项目根目录即pom.xml文件所在的同级目录,可以在项目根目录下创建文件夹lib,如下…

持续集成之 Spring Boot 实战篇

本文作者: CODING 用户 - 何健 这次实战篇,我们借助「CODING 持续集成」,实现一个简单的 Spring Boot 项目从编码到最后部署的完整过程。本教程还有 B 站视频版,帮助读者更好地学习理解。 思路 在线上环境构建、测试、部署 这种情…

java静态工厂方法模式_设计模式:简单工厂模式(静态工厂方法模式)

简单工厂的构成包括三个角色:1)抽象产品类2)具体产品类(继承抽闲产品类)3)工厂类(生产具体产品)具体代码实现1、抽象产品类/*** 抽象类*/public abstract class Car {/*** 产品抽象方法,将会由具体产品类实现*/public abstract void driving();}2、具体产…

Kibana中的Coordinate Map地图报索引错误的问题

今天做地图定位展示,展示的是ApacheWeb服务器的访问日志文件中的来源IP。但是中间出现了报错环节,说是索引不能匹配到geo_point类型,实在是不懂这是在说什么,后来在网站找了方法就解决了。主要报错如下: 报错信息&…

mysql数据库安装在unix_Linux下的数据库二:在Linux/Unix平台安装MySQL

推荐使用RPM工具来进行Linux下的MySQL数据库安装。目前的MySQLrpm安装文件包是在SuSE Linux7.3系统平台上打造而成的,但是在绝大多数支持RPM和glibc的其他Linux平台中也可以进行安装。如果选择通用的RPM安装包,那么RPM将静态链接到Linux的线程中。下面步…

mysql时区设置gmt_将MySQL数据库时区设置为GMT

不,不可能在MySQL实例中更改单个数据库的时区.您可以检索服务器和客户端time_zone设置:SELECT global.time_zone, session.time_zone;您还可以更改整个MySQL实例的客户端时区或时区.但要敏锐地了解现有客户端连接的含义,以及如何解释已存储在实例中的DATETIME和TIME…

javaSE知识点汇总

javaSE知识点汇总Java基础知识精华部分写代码:1,明确需求。我要做什么?2,分析思路。我要怎么做?1,2,3。3,确定步骤。每一个思路部分用到哪些语句,方法,和对象。4,代码实现…

java中412是什么错_HTTP 412 错误 – 先决条件失败 (Precondition failed)

HTTP 412 错误 – 先决条件失败 (Precondition failed)介绍您的 Web 服务器认为,该服务器检测到客户端发送的 HTTP 数据流包括一个没有满足的‘先决条件’规范。HTTP 循环中的 412 错误任何客户端 ( 例如您的浏览器或我们的 CheckUpDown 机器人 ) ,都需要…