有人能告诉我同步方法比同步块的优势与一个例子吗?
当前回答
通常在方法级别上使用锁是不礼貌的。为什么要通过锁定整个方法来锁定一段不能访问任何共享资源的代码呢?因为每个对象都有一个锁,所以可以创建虚拟对象来实现块级同步。 块级的效率更高,因为它不锁定整个方法。
这里有一些例子
方法级
class MethodLevel {
//shared among threads
SharedResource x, y ;
public void synchronized method1() {
//multiple threads can't access
}
public void synchronized method2() {
//multiple threads can't access
}
public void method3() {
//not synchronized
//multiple threads can access
}
}
块级别
class BlockLevel {
//shared among threads
SharedResource x, y ;
//dummy objects for locking
Object xLock = new Object();
Object yLock = new Object();
public void method1() {
synchronized(xLock){
//access x here. thread safe
}
//do something here but don't use SharedResource x, y
// because will not be thread-safe
synchronized(xLock) {
synchronized(yLock) {
//access x,y here. thread safe
}
}
//do something here but don't use SharedResource x, y
//because will not be thread-safe
}//end of method1
}
(编辑)
对于像Vector和Hashtable这样的集合,当ArrayList或HashMap不同步时,它们是同步的,你需要设置synchronized关键字或调用Collections synchronized方法:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
其他回答
在实际应用中,同步方法相对于同步块的优势在于它们更能抵抗白痴;因为您不能选择任意对象来锁定,所以您不能滥用synchronized方法语法来做一些愚蠢的事情,比如锁定字符串文字或锁定从线程下面更改的可变字段的内容。
另一方面,使用同步方法,您无法保护锁不被任何可以获得对象引用的线程获取。
因此,在方法上使用synchronized作为修饰符可以更好地保护你的奶牛免受伤害,而将synchronized块与私有final锁对象结合使用则可以更好地保护你自己的代码免受奶牛的伤害。
使用同步块,您可以有多个同步器,因此多个同时但不冲突的事情可以同时进行。
唯一真正的区别是同步块可以选择在哪个对象上同步。同步方法只能使用'this'(或同步类方法的相应Class实例)。例如,它们在语义上是等价的:
synchronized void foo() {
...
}
void foo() {
synchronized (this) {
...
}
}
后者更灵活,因为它可以竞争任何对象(通常是成员变量)的关联锁。它也更细粒度,因为您可以在块之前和块之后执行并发代码,但仍然在方法中。当然,您也可以通过将并发代码重构为单独的非同步方法来轻松地使用同步方法。使用任何使代码更容易理解的方法。
通常在方法级别上使用锁是不礼貌的。为什么要通过锁定整个方法来锁定一段不能访问任何共享资源的代码呢?因为每个对象都有一个锁,所以可以创建虚拟对象来实现块级同步。 块级的效率更高,因为它不锁定整个方法。
这里有一些例子
方法级
class MethodLevel {
//shared among threads
SharedResource x, y ;
public void synchronized method1() {
//multiple threads can't access
}
public void synchronized method2() {
//multiple threads can't access
}
public void method3() {
//not synchronized
//multiple threads can access
}
}
块级别
class BlockLevel {
//shared among threads
SharedResource x, y ;
//dummy objects for locking
Object xLock = new Object();
Object yLock = new Object();
public void method1() {
synchronized(xLock){
//access x here. thread safe
}
//do something here but don't use SharedResource x, y
// because will not be thread-safe
synchronized(xLock) {
synchronized(yLock) {
//access x,y here. thread safe
}
}
//do something here but don't use SharedResource x, y
//because will not be thread-safe
}//end of method1
}
(编辑)
对于像Vector和Hashtable这样的集合,当ArrayList或HashMap不同步时,它们是同步的,你需要设置synchronized关键字或调用Collections synchronized方法:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
唯一的区别是:同步块允许颗粒状锁定,不像同步方法
基本上同步块或方法被用来编写线程安全的代码,以避免内存不一致的错误。
这个问题很老了,在过去的7年里,很多事情都发生了变化。 为了线程安全,引入了新的编程结构。
您可以通过使用高级并发API而不是同步块来实现线程安全。该文档页提供了实现线程安全的良好编程结构。
锁对象支持简化许多并发应用程序的锁定习惯用法。
executor为启动和管理线程定义了高级API。concurrent提供的执行器实现提供了适合大型应用程序的线程池管理。
并发集合使管理大型数据集合变得更容易,并且可以大大减少同步的需要。
原子变量具有最小化同步和帮助避免内存一致性错误的特性。
ThreadLocalRandom(在JDK 7中)提供了从多个线程有效生成伪随机数的功能。
更好的synchronized替代品是ReentrantLock,它使用Lock API
一个可重入互斥锁,其基本行为和语义与使用同步方法和语句访问的隐式监视锁相同,但具有扩展功能。
锁的例子:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
其他编程结构也可以参考java.util.concurrent和java.util.concurrent.atomic包。
参考这个相关的问题:
同步vs锁定
推荐文章
- 在Java中从字符串中提取数字
- 套接字的连接超时和读超时之间的区别是什么?
- Java整数到字节数组
- 如何设置Windows环境下Java的环境变量
- Java Swing revalidate() vs repaint()
- Java中文件中的行数
- 指定的子节点已经有一个父节点。你必须先在子对象的父对象上调用removeView() (Android)
- 对于一个布尔字段,它的getter/setter的命名约定是什么?
- 如何获得当前屏幕方向?
- 如何在Android中渲染PDF文件
- 如何计算一个元素在列表中出现的次数
- c++中类似于java的instanceof
- 我如何解决错误“minCompileSdk(31)指定在一个依赖的AAR元数据”在本机Java或Kotlin?
- 如何POST表单数据与Spring RestTemplate?
- Mockito中检测到未完成的存根