虽然这个问题可能会在SO上被问几次(主要以 this
与 Synchronized block 中的 Bar.clas
的形式),但我不清楚类的静态引用/对象的同步(第三个示例) )这个问题。请看下面的 Java 示例:
示例#1 -
synchronized
阻止this
关键字公共(public)类 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(); }
}
结果:当任何来自 t1,t2,t3
的线程时通过同步块(synchronized block)获取锁(例如t1
获取),然后t2
和t3
将处于阻塞状态,但同时其他线程t4
, t5
和t6
允许同时执行。
示例#2 -
synchronized
阻止Bar.class
公共(public)类 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(); } }
结果: Bar
的任何实例中只有一个线程类,将获取锁(例如 t1
获取锁),并且所有其他线程( t2,t3...t6
)将被阻塞,直到 t1
释放锁。
- 示例#3 -
synchronized
阻止static
引用/对象
公共(public)类 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();
}
}
问题:
使用
static
会产生什么效果?synchronized
中的引用/对象 block (如示例#3)在
synchronized
中使用非静态引用/对象会产生什么效果?阻止。静态引用
NUM
也是如此在同步块(synchronized block)(synchronized(NUM)
)中相当于synchronized(Bar.class)
?
最佳答案
在同步块(synchronized block)中使用静态引用/对象会产生什么效果(如示例#3)
静态对象在线程之间共享,因此当一个线程获取锁时,所有线程都会阻塞。 这意味着如果 t1 在同步块(synchronized block)内,则 t2、t3、...、t6 会被阻塞。
但是您提供的代码中有一个技巧。 NUM++
这将创建一个新的 NUM 对象,因为 Integer 类是不可变的。那么会发生什么,假设 t1 获取锁并进入同步块(synchronized block)。现在,t1 执行 NUM++
。现在可能会发生很多情况。
- 如果在执行 Num++ 之前另一个线程被阻塞,则该线程将保持阻塞状态,直到 t1 退出同步块(synchronized block)。
- 如果线程没有被阻塞(比如 t2)并且 Num++ 由 t1 执行,那么 t2 将不会阻塞,因为 Num 现在是一个新的 Integer。因此锁是不同的 t2 进入为新 Integer 获取锁的 block 。
所有线程都可能发生同样的故事。 事实上,所有线程同时处于同步块(synchronized block)中是可能的。
在同步块(synchronized block)中使用非静态引用/对象会产生什么效果。
假设 Bar 类的实例之间不共享非静态对象,则同步块(synchronized block)中只能有 t1、t2、t3 一个线程。 t4、t5、t6 类似。但是,如果它是共享的,则与静态对象具有相同的效果。
同步块(synchronized block)中的静态引用 NUM (synchronized(NUM)) 是否等同于 synchronized(Bar.class) ?
如果你不按照我在第一个问题的答案中解释的那样更改 NUM
关于java - 多线程环境中具有静态引用/对象的同步块(synchronized block),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27561501/