虽然可以在SO上多次询问这个问题(主要是在同步块中以 this
与 Bar.clas
的形式),但我不清楚这个问题的类(第3个例子)的静态参考/对象上的同步 . 请看下面的Java示例:
- Example#1 -
synchronized
阻止this
关键字
公共类Bar实现Runnable {
@Override
public void run() {
objectLock();
}
public void objectLock() {
synchronized(this) {
System.out.println(Thread.currentThread().getName());
System.out.println("synchronized block " + Thread.currentThread().getName());
System.out.println("synchronized block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Bar b1 = new Bar();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Thread t3 = new Thread(b1);
Bar b2 = new Bar();
Thread t4 = new Thread(b2);
Thread t5 = new Thread(b2);
Thread t6 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t4.setName("t4");
t5.setName("t5");
t6.setName("t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
Result :当来自 t1,t2,t3
的任何线程通过synchronized块获取锁定(比如 t1
acquire),那么 t2
和 t3
将处于 blocked 状态,但同时允许其他线程 t4
,_ t5
和 t6
执行 concurrently .
- Example#2 -
synchronized
阻止Bar.class
公共类Bar实现Runnable {
@Override
public void run() {
objectLock();
}
public void objectLock() {
synchronized(Bar.class) {
System.out.println(Thread.currentThread().getName());
System.out.println("synchronized block " + Thread.currentThread().getName());
System.out.println("synchronized block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Bar b1 = new Bar();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Thread t3 = new Thread(b1);
Bar b2 = new Bar();
Thread t4 = new Thread(b2);
Thread t5 = new Thread(b2);
Thread t6 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t4.setName("t4");
t5.setName("t5");
t6.setName("t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
Result :只有 Bar
类的任何实例的一个线程将获得锁定(比如 t1
获取锁定),所有其他线程( t2,t3...t6
)将被阻止,直到 t1
释放锁定 .
- Example#3 -
synchronized
阻止static
Reference / Object
公共类Bar实现Runnable {
private static Integer NUM=new Integer(5);
@Override
public void run() {
objectLock();
}
public void objectLock() {
synchronized(NUM) {
System.out.println(Thread.currentThread().getName());
System.out.println(NUM++);
System.out.println("synchronized block " + Thread.currentThread().getName());
System.out.println("synchronized block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Bar b1 = new Bar();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Thread t3 = new Thread(b1);
Bar b2 = new Bar();
Thread t4 = new Thread(b2);
Thread t5 = new Thread(b2);
Thread t6 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t4.setName("t4");
t5.setName("t5");
t6.setName("t6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
Question :
-
在
synchronized
块中使用static
reference / object会有什么影响(如 Example#3 ) -
在
synchronized
块中使用 non-static reference / object会产生什么影响 . -
同步块(
synchronized(NUM)
)中的静态引用NUM
是否等同于synchronized(Bar.class)
?
3 回答
What would be the effect of using static reference/object in synchronized block (as in Example#3)
静态对象在线程之间共享,因此当一个线程获取锁时将阻塞所有线程 . 意味着如果t1在同步块内,则t2,t3,...,t6被阻止 .
But 您提供的代码中有一个技巧 .
NUM++
这将创建一个新的NUM对象,因为Integer类是不可变的 . 那么会发生什么,比如t1获取锁并进入同步块 . 现在,t1执行NUM++
. 现在很多情况都会发生 .如果在执行Num之前另一个线程被阻塞,则该线程将保持阻塞,直到t1退出同步块 .
如果一个线程没有被阻塞(比如t2)并且Num被t1执行,那么t2将不会阻塞,因为Num现在是一个新的Integer . 因此锁定是不同的,并且t2进入块获取新Integer的锁定 .
所有线程都可能发生同样的故事 . In fact, it is possible to have all the threads in the synchronized block at the same time.
What would be the effect of using non-static reference/object in synchronized block.
假设在类Bar的实例之间不共享非静态对象,因此只有t1,t2,t3的一个线程可以在同步块中 . 类似地,对于t4,t5,t6 . 但是,如果它是共享的,它与静态对象具有相同的效果 .
Also does the Static reference NUM in synchronized block (synchronized(NUM)) is equivalent to synchronized(Bar.class) ?
如果您没有像我在第一个问题的答案中解释的那样更改NUM
互斥锁是静态的还是非静态的并不重要,只要它是同一个对象 .
要回答第一个问题,
NUM
对象对于所有线程都是相同的,因此没有两个线程可以同时获取锁定 .第二个问题更棘手......如果
synchronized
块中的对象对于所有线程都是相同的,那么它们将像在前一个场景中那样执行 . 如果每个线程都有自己的对象,那么就没有什么能阻止你的所有线程一次进入临界区 .此外,请记住,当您调用
t2.start()
时,可能已经完成处理(同样可能发生在您的其他线程中),因此请确保您不会被您在控制台上看到的内容所迷惑...在回答您的问题之前您需要了解以下几点 .
以上所有同步在对象或类级别中具有不同级别的互斥锁 .
What is Mutex
在Java中,每个对象都只有一个监视器和与之关联的监视器 . 单个监视器有几个门,但每个都由synchronized关键字指示 . 当一个线程通过synchronized关键字时,它会有效地锁定所有门 . 当然,如果一个线程没有锁定门,而其他一些线程在任何时候都是自由驳船 . 资料来源:Click here
Synchronization block with this/Synchronized Instance Method
互斥锁将应用于当前对象 .
Mutext将在所有 instance method 中共享 .
例如:Thread_1和Thread_2分别是调用方法
a
和b
. 所以任何一个线程都会等待其他人 . Thread_3调用方法a
或b
它将按照之前的语句等待 .Synchronization block with .class/Synchronized static Method
Mutex将应用于该类的类对象 .
Mutext将在所有 static method 中共享 .
Thread_1和Thread_2分别是调用方法
a
和b
. 所以任何一个线程都会等待其他人 . Thread_3调用方法a
或b
它将按照之前的语句等待 . 该类的所有对象和静态引用对于那些 static methods 具有相同的互斥锁 .注意:同步实例方法将在对象级别具有互斥锁 . 所以它不会影响上述条件 .
Synchronization block with instance reference/object.
互斥锁将应用于实例级别的用户定义对象 .
一个互斥对象将使用一个或多个实例方法 .
如果Thread_1和Thread_2分别调用a和b . 两者都会被授予 . 如果Thread_3调用
c
或a
. 它将等待Thread_1完成 . 所以我们可以在实例级别的每个方法中定义锁 .Synchronization block with static reference/object.
互斥锁将应用于类级别的用户定义对象 .
一个互斥对象将使用一个或多个实例方法 .
它就像instanse参考一样 . 但是互斥体在所有类的实例中都是一样的 . 因此,如果thread_1,thread_2调用
a
方法,则只有一个thread_1将获得锁定 . 其他人会等因为它的 class 水平 .