虽然可能会在SO上多次询问此问题(主要是在同步块中以this
与Bar.clas
的形式),但我不清楚静态参考/对象的同步这个问题的类(第3个例子)。请看下面的Java示例:
示例#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();
}
}
结果:来自t1,t2,t3
的任何帖子通过已同步的块获取锁定(比如t1
获取),然后t2
和t3
将是在阻止状态,但同时允许其他线程t4
,t5
和t6
执行并发。
示例#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();
}
}
结果:Bar
类的任何实例中只有一个线程将获得锁定(比如t1
获取锁定)和所有其他线程(t2,t3...t6
)将被阻止,直到t1
释放锁定。
synchronized
阻止static
参考 / 对象 公共类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
引用/对象会产生什么影响(如示例#3 )
在synchronized
阻止中使用非静态引用/对象会产生什么影响。
同步块(NUM
)中的静态参考synchronized(NUM)
是否等同于synchronized(Bar.class)
?
答案 0 :(得分:2)
在synchronized块中使用静态引用/对象会产生什么影响(如例#3)
静态对象在线程之间共享,因此当一个线程获取锁时将阻塞所有线程。 意思是如果t1在同步块内,则t2,t3,...,t6被阻止。
但是您提供的代码中有一个技巧。 NUM++
这将创建一个新的NUM对象,因为Integer类是不可变的。那么会发生什么,比如t1获取锁并进入同步块。现在,t1执行NUM++
。现在很多情况都会发生。
所有主题都可能发生同样的情况。 实际上,可以同时拥有同步块中的所有线程。
在同步块中使用非静态引用/对象会产生什么影响。
假设在类Bar的实例之间没有共享非静态对象,因此只有t1,t2,t3的一个线程可以在synchronized块中。类似地,对于t4,t5,t6。但是,如果它是共享的,它与静态对象具有相同的效果。
同步块中的静态引用NUM(synchronized(NUM))是否等同于synchronized(Bar.class)?
如果你没有像我在第一个问题的答案中解释的那样改变NUM
答案 1 :(得分:1)
互斥锁是静态的还是非静态的,只要它是同一个对象就没关系。
要回答第一个问题,NUM
对象对于所有线程都是相同的,因此没有两个线程可以同时获取锁定。
第二个问题更棘手......如果synchronized
块中的对象对于所有线程都相同,那么它们的执行方式与前一个场景中的相同。如果每个线程都有自己的对象,那么就没有什么能阻止你的所有线程一次进入关键部分。
此外,请记住,当您致电t2.start()
时,很可能t1可能已经完成处理(同样可能发生在您的其他线程中),因此请确保您不会被愚弄通过你在控制台上看到的内容......
答案 2 :(得分:0)
在回答您的问题之前您需要了解以下几点。
以上所有同步在对象或类级别中都具有不同级别的互斥锁。
什么是Mutex
在Java中,每个对象都有一个且只有一个与之关联的监视器和互斥锁。单个监视器有几个门,但每个都由synchronized关键字指示。当一个线程经过synchronized关键字时,它会有效地锁定所有门。当然,如果一个帖子没有通过synchronized关键字,它就没有锁定门,而其他一些线程在任何时候都是免费的。资料来源:Click here
使用this
/同步实例方法
public class Test {
public synchronized void a() {
}
public void b() {
synchronized(this) {
}
}
}
例如:Thread_1& Thread_2分别是调用方法a
和b
。所以任何一个线程都会等待其他人。 Thread_3调用方法a
或b
它将按照之前的语句等待。
使用.class
/同步静态方法
public class Test {
public static synchronized void a() {
}
public static void b() {
synchronized(Test.class) {
}
}
}
Thread_1& Thread_2分别是调用方法a
和b
。所以任何一个线程都会等待其他人。 Thread_3调用方法a
或b
它将按照之前的语句等待。该类的所有对象和静态引用对于那些静态方法具有相同的互斥锁。
注意:同步实例方法将在对象级别具有互斥锁。所以它不会影响上述条件。
与instance reference/object
的同步阻止。
public class Test {
Object obj1 = new Object();
Object obj2 = new Object();
public void a() {
synchronized (obj1) {
}
}
public void b() {
synchronized(obj2) {
}
}
public void c() {
synchronized (obj1) {
}
}
}
如果Thread_1和Thread_2分别调用a和b。两者都会被授予。如果Thread_3调用c
或a
。它将等待Thread_1完成。所以我们可以在实例级别的每个方法中定义锁。
与static reference/object
的同步阻止。
public class Test {
static Object obj1 = new Object();
static Object obj2 = new Object();
public void a() {
synchronized (obj1) {
}
}
public void b() {
synchronized(obj2) {
}
}
public void c() {
synchronized (obj1) {
}
}
}
就像instanse参考一样。但是互斥体在所有类的实例中都是一样的。
因此,如果thread_1,thread_2调用a
方法,则只有一个thread_1将获得锁定。其他人会等
因为它的班级水平。