[英]synchronized block with static reference/object in multi-threading environment
尽管这个问题可能会问几个时间上SO(主要是在形式this
VS Bar.clas
在synchronized块或多个),但我不清楚在这个问题上的静态参考/对象的类(第三个例子)的同步。 请看下面的Java示例:
Example#1-使用this
关键字的synchronized
块
公共类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
同时执行。
Example#2-与Bar.class
synchronized
块
公共类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
释放锁为止。
static
引用 / 对象的 synchronized
块 公共类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();
}
}
问题 :
在synchronized
块中使用static
引用/对象会有什么影响(如Example#3所示 )
在synchronized
块中使用非静态参考/对象会有什么影响。
另外,同步块synchronized(Bar.class)
synchronized(NUM)
)中的静态引用NUM
是否等效于synchronized(Bar.class)
?
在同步块中使用静态引用/对象会有什么影响(如示例3)
静态对象在线程之间共享,因此,一个线程获得锁时将阻塞的所有线程。 这意味着如果t1在同步块内,则将阻塞t2,t3,...,t6。
但是您提供的代码中有一个技巧。 NUM++
这将创建一个新的NUM对象,因为Integer类是不可变的。 所以说t1将获得锁定并进入同步块,将会发生什么。 现在,t1执行NUM++
。 现在可能发生许多情况。
所有线程都可能发生相同的情况。 实际上,可以将所有线程同时放在同步块中。
在同步块中使用非静态参考/对象会有什么影响。
假定在类Bar的实例之间不共享非静态对象,则在同步块中只能有一个线程t1,t2,t3。 对于t4,t5,t6同样。 但是,如果共享它,则其效果与静态对象相同。
同步块(synchronized(NUM))中的静态引用NUM是否也等于synced(Bar.class)?
这是您是否不更改我在第一个问题的答案中所述的NUM
互斥对象是静态的还是非静态的都没有关系,只要它是同一对象即可。
为了回答您的第一个问题,所有线程的NUM
对象都是相同的,因此,没有两个线程能够同时获得对其的锁定。
第二个问题更加棘手...如果synchronized
块中的对象对于所有线程都是相同的,则它们的性能将与上一个方案中的相同。 如果每个线程都有自己的对象,那么将无法阻止您的所有线程一次进入临界区。
另外,请记住,当您调用t2.start()
t1可能已经完成处理(其他线程也可能发生这种情况t2.start()
可能性很大,因此请确保不要被看到的打印在屏幕上的东西所迷惑。安慰...
在提出问题之前,您需要了解以下几点。
上述所有同步将在对象或类级别具有不同级别的互斥锁。
什么是互斥体
在Java中,每个对象都有一个,并且只有一个与之关联的监视器和互斥体。 单个监视器具有多个门,但是每个门都由synced关键字指示。 当线程经过synced关键字时,它将有效地锁定所有门。 当然,如果某个线程没有跨过synced关键字,则它没有将门锁上,并且其他任何线程都可以随时插入。 来源: 点击这里
使用this
/ Synchronized Instance方法的同步块
public class Test {
public synchronized void a() {
}
public void b() {
synchronized(this) {
}
}
}
例如:Thread_1和Thread_2分别是调用方法a
和b
。 因此,线程之一将等待其他线程。 Thread_3调用方法a
或b
,它将按照前面的语句等待。
.class
/ Synchronized静态方法的同步块
public class Test {
public static synchronized void a() {
}
public static void b() {
synchronized(Test.class) {
}
}
}
线程_1和线程_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) { } } }
就像即时参考一样。 但是互斥锁在该类的所有实例中都相同。 因此,如果thread_1,thread_2调用a
方法,则只有一个thread_1将获得锁。 其他将等待。 因为它的阶级水平。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.