Java 关于同步方法、锁和监视器的说明
为了加深我对Java同步的了解,我的困惑始于以下语句,摘自: Java中的每个对象都与一个监视器相关联,线程可以锁定或解锁该监视器。[…]如果[synchronized]方法主体的执行正常或突然完成,则会在同一监视器上自动执行解锁操作 所以,我想象一个监视器就像一个圆顶,覆盖整个对象,防止两个线程同时访问它。更清楚地说,我认为Java 关于同步方法、锁和监视器的说明,java,multithreading,synchronization,Java,Multithreading,Synchronization,为了加深我对Java同步的了解,我的困惑始于以下语句,摘自: Java中的每个对象都与一个监视器相关联,线程可以锁定或解锁该监视器。[…]如果[synchronized]方法主体的执行正常或突然完成,则会在同一监视器上自动执行解锁操作 所以,我想象一个监视器就像一个圆顶,覆盖整个对象,防止两个线程同时访问它。更清楚地说,我认为 class MySync{ synchronized void foo(){} void bar(){} String x; } 如果threa
class MySync{
synchronized void foo(){}
void bar(){}
String x;
}
如果threadA访问并运行(同步)foo()
方法5秒,它将“激活圆顶”,防止threadB访问对象的任何其他成员,如条或x
我写这些代码只是为了做一些测试,我发现我错了
public class Main{
public static void main(String args[]) throws InterruptedException{
new Main();
}
MySync ms = new MySync();
RunnableA r1=new RunnableA(ms);
RunnableB r2=new RunnableB(ms);
Main() throws InterruptedException{
r1.start();
Thread.sleep(1000);
r2.start();
}
}
class MySync{
synchronized void foo(String tab){
System.out.println(tab+Thread.currentThread().getName()+" in foo()");
if("A".equals(Thread.currentThread().getName())){
System.out.println(tab+Thread.currentThread().getName()+" Waiting 5 seconds");
try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println(tab+Thread.currentThread().getName()+" out foo()");
}
void bar(String tab){
System.out.println(tab+Thread.currentThread().getName()+" in bar()");
System.out.println(tab+Thread.currentThread().getName()+" out bar()");
}
}
class RunnableA implements Runnable{
String tab="";
Thread t=new Thread(this);
MySync ms;
RunnableA(MySync ms){
this.ms=ms;
t.setName("A");
}
void start(){t.start();}
@Override
public void run(){
System.out.println(tab+"A Running ");
ms.foo(tab);
System.out.println(tab+"A End running");
}
}
class RunnableB implements Runnable{
String tab=" ";
Thread t=new Thread(this);
MySync ms;
RunnableB(MySync ms){
this.ms=ms;
t.setName("B");
}
void start(){t.start();}
@Override
public void run(){
System.out.println(tab+"B Running ");
ms.bar(tab);
System.out.println(tab+"B End running");
}
}
这是输出:
A Running
A in foo()
A Waiting 5 seconds //threadA stuck in syncronized foo() method
B Running //threadB accesses bar() method anyway
B in bar()
B out bar()
B End running
A out foo()
A End running
我的问题是:
Java中的每个对象都与监视器关联,这意味着什么?这不是有点模棱两可吗?如果我也声明synchronizedbar()
,我会得到预期的行为。这是否意味着我的虚拟穹顶一次只覆盖所有同步方法(即,所有同步方法都有一个锁)?是的,虚拟穹顶只覆盖该对象的所有同步方法以及该对象上显式同步的代码片段,如:
,,,
synchronize(this) {
doSomething();
}
并非代码的所有部分都对线程安全敏感,因此某些方法可以在同一对象中“不同步”,从而加快执行速度
“Java中的每个对象都与监视器关联意味着什么?”
这意味着每个对象上都有可用的监视器。您可以通过在对象上声明synchronized方法或使用synchronized(obj)方法来访问它。因此,您不需要引入另一个提供监控功能的“实体”。
对于适当的监视器,您可以访问每个对象上的wait()和notify()方法
syncrhonize(obj) {
while(someConditionIsNotTrue) {
obj.wait();
}
}
因此,只要代码的逻辑需要以独占方式访问对象,就可以使用内置监视器并在其上调用synchronize
为了提供线程安全性,所有部件都必须按照相同的规则运行,并在需要时使用同步。为了防止由于遗漏而导致的错误,有更高级别的并发机制,如AtomicInteger和ConcurrentCollections 同步是一种开发人员工具,可用于在线程之间协调访问资源
美国
synchronized
语句在
代表执行线程执行一个块,然后释放
锁当执行线程拥有锁时,其他线程不能拥有
获取锁。
在您的例子中,线程A
获取锁并执行foo
,该操作已实现为需要锁。然后,线程B
执行bar
,该线程尚未实现以要求锁定<代码>B
因此未被阻止
再次从规范中删除
获取与对象关联的锁本身不起作用
阻止其他线程访问对象的字段或调用
对象上的非同步方法。其他线程也可以使用
synchronized方法或常规方法中的synchronized语句
实现互斥的方式
将同步视为各方之间的协议,即必须通过同步目标来访问某些内容。如果某些代码忽略此协议并直接访问该内容,则可能会导致中提到的线程干扰和内存一致性错误。为了处理此dome机制,每个Java对象都存在一个类型为lock flag
的标志,并且使用synchronized
允许根据以下模式与该锁定标志交互
调用synchronized(this)后,锁标志将由线程保持,直到它完成处理或经历某些特定的中断情况
当锁标志由第一个线程获取时,如果第二个线程出现并尝试访问由引用的对象,则该
将无法访问,因为没有锁标志。因此,线程调度程序将把新线程放在等待对象锁定标志的线程池中。它将一直停留在那里,直到释放锁标志,并且根据线程调度器的调度决定,它可能会立即访问对象,也可能不会立即访问对象
发生以下事件时,将释放锁定标志
- 线程通过同步代码块的末尾
- 同步代码块引发中断、返回或异常时
为了正确使用synchronize,务必确保
- 对精细数据的所有访问都是同步的(您应该这样做)
- 所有受synchronized保护的精致数据都必须是私有的
嗯,我花了一段时间才意识到,我真的需要确认。我感到惊讶的是,即使是语言规范对如此微妙的主题也显得如此综合和仓促。你的第二次引用非常明确,我不得不承认我错过了它。但是,再一次让我惊讶的是,这句话是在关于语句的段落的最后几行报告的(当我研究方法时),而不是在更一般的讨论中