Answers:
两种方法都锁定同一监视器。因此,您不能同时在不同线程上的同一对象上执行它们(两种方法之一将阻塞,直到另一种方法完成)。
obj.methodB()
是同义A.methodB()
的时候methodB()
是static
。因此,是的,它们将阻塞(在类的监视器上,而不在对象的监视器上)。
.class
对象使用锁定。所以如果你有class A {static synchronized void m() {} }
。然后一个线程调用new A().m()
它获取对new A()
对象的锁定。如果然后另一个线程调用A.m()
它,则进入“方法无问题”,因为它所寻找的是A.class
对象上的锁,而没有线程拥有这种锁。因此,即使你声明的方法synchronized
它actualy 访问由两个不同的线程在同一时间。因此:永远不要使用对象引用来调用静态方法
在示例methodA和methodB是实例方法(与静态方法相反)。放置synchronized
实例方法意味着线程必须在该线程可以开始执行该方法中的任何代码之前,获取对该方法所调用的对象实例的锁定(“固有锁定”)。
如果您有两个不同的实例方法标记为已同步,并且不同的线程正在同一对象上并发调用这些方法,则这些线程将争用同一把锁。一旦一个线程获得了锁,则所有其他线程将从该对象上所有同步的实例方法中退出。
为了使两种方法同时运行,它们将必须使用不同的锁,如下所示:
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
其中,同步块语法允许指定执行线程需要获取固有锁定才能进入该块的特定对象。
需要了解的重要一点是,即使我们在各个方法上都使用了“ synchronized”关键字,但核心概念仍然是幕后的内在锁。
下面是如何在Java教程介绍的关系:
同步是围绕称为内部锁或监视器锁的内部实体构建的。(API规范通常将此实体简称为“监视器”。)内在锁在同步的两个方面都起作用:强制对对象状态的独占访问并建立对可见性至关重要的事前关联。
每个对象都有一个与之关联的固有锁。按照惯例,需要对对象的字段进行独占且一致的访问的线程必须在访问对象之前先获取对象的固有锁,然后在完成对它们的锁定后释放固有锁。据说线程在获得锁和释放锁之间拥有该内部锁。只要一个线程拥有一个内在锁,其他任何线程都无法获得相同的锁。另一个线程在尝试获取锁时将阻塞。
锁定的目的是保护共享数据。仅当每个锁保护不同的数据成员时,才使用上面的示例代码中所示的单独的锁。
static synchronized
或synchronized (A.class)
Java Thread 进入实例同步的java方法时将获取对象级别的锁定,而进入静态同步的java方法时将获取类级别的锁定。
在您的情况下,方法(实例)属于同一类。因此,无论何时线程进入Java同步方法或阻塞,它都会获取一个锁(调用该方法的对象)。因此,在第一个方法完成并释放锁(在对象上)之前,无法在同一对象上同时调用其他方法。
private final Object lock = new object();
与sync一起使用,以仅允许一个线程执行两种方法中的任何一种吗?谢谢
在您的情况下,您在同一个类实例上同步了两个方法。因此,这两种方法不能同时在类A的同一实例的不同线程上运行。但是它们可以在不同的类A的实例上运行。
class A {
public synchronized void methodA() {
//method A
}
}
是相同的:
class A {
public void methodA() {
synchronized(this){
// code of method A
}
}
}
private final Object lock = new Object();
并且现在lock
在两种方法中与同步块一起使用怎么办,那么您的语句将成立吗?IMO由于Object是所有对象的父类,因此即使线程在该类的不同实例上,一次也只能访问同步块内的代码。谢谢。
将您的代码视为以下代码:
class A {
public void methodA() {
synchronized(this){
//method A body
}
}
public void methodB() {
synchronized(this){
// method B body
}
}
因此,在方法级别同步仅表示已同步(此)。如果任何线程运行此类的方法,它将在开始执行之前获取该锁,并保持该锁直到该方法的执行完成。
但是,可以在methodA()仍在运行时在不同的线程上运行methodB()吗?(相同的对象)
确实,这是不可能的!
因此,多个线程将无法同时在同一对象上运行任何数量的同步方法。
同步的主要思想是不容易陷入,它只有在相同的对象实例上调用方法时才会生效-答案和注释中已经突出显示了同步-
下面的示例程序是要明确指出相同的地方-
public class Test {
public synchronized void methodA(String currentObjectName) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}
public synchronized void methodB(String currentObjectName) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}
public static void main(String[] args){
Test object1 = new Test();
Test object2 = new Test();
//passing object instances to the runnable to make calls later
TestRunner runner = new TestRunner(object1,object2);
// you need to start atleast two threads to properly see the behaviour
Thread thread1 = new Thread(runner);
thread1.start();
Thread thread2 = new Thread(runner);
thread2.start();
}
}
class TestRunner implements Runnable {
Test object1;
Test object2;
public TestRunner(Test h1,Test h2) {
this.object1 = h1;
this.object2 = h2;
}
@Override
public void run() {
synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
//noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}
// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
try {
object1.methodA("object1");
object1.methodB("object1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
try {
object1.methodA("object1");
object2.methodB("object2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
注意,如果在不同的对象实例上调用方法,则按预期如何允许同时访问的输出有所不同。
带有noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects() 注释的输出-输出按以下顺序排序:methodA in> methodA Out .. methodB in> methodB Out
和Ouput,其中带有syncedEffectiveAsMethodsCalledOnSameObject ()的 评论为注释 -输出在突出显示的部分中显示了Thread1和Thread0同时访问methodA-
增加线程数将使其更加引人注目。