繁体   English   中英

多线程环境中具有静态引用/对象的同步块

[英]synchronized block with static reference/object in multi-threading environment

尽管这个问题可能会问几个时间上SO(主要是在形式this VS Bar.clas在synchronized块或多个),但我不清楚在这个问题上的静态参考/对象的类(第三个例子)的同步。 请看下面的Java示例:

  1. 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获取)时,则t2t3将处于阻塞状态,但同时允许其他线程t4t5t6 同时执行。

  1. 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释放锁为止。

  1. Example#3-带有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();

}

}

问题

  1. synchronized块中使用static引用/对象会有什么影响(如Example#3所示

  2. synchronized块中使用非静态参考/对象会有什么影响。

  3. 另外,同步块synchronized(Bar.class) synchronized(NUM) )中的静态引用NUM是否等效于synchronized(Bar.class)

在同步块中使用静态引用/对象会有什么影响(如示例3)

静态对象在线程之间共享,因此,一个线程获得锁时将阻塞的所有线程。 这意味着如果t1在同步块内,则将阻塞t2,t3,...,t6。

但是您提供的代码中有一个技巧。 NUM++这将创建一个新的NUM对象,因为Integer类是不可变的。 所以说t1将获得锁定并进入同步块,将会发生什么。 现在,t1执行NUM++ 现在可能发生许多情况。

  1. 如果在执行Num ++之前另一个线程被阻塞,则该线程将保持阻塞状态,直到t1退出同步块为止。
  2. 如果没有阻塞线程(例如t2),并且t1执行了Num ++,则t2将不会阻塞,因为Num现在是一个新的Integer。 因此,锁是不同的,t2进入获取新Integer锁的块。

所有线程都可能发生相同的情况。 实际上,可以将所有线程同时放在同步块中。

在同步块中使用非静态参考/对象会有什么影响。

假定在类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方法的同步块

  • 互斥对象将应用于当前对象。
  • Mutext将在所有实例方法之间共享。

      public class Test {    
            public synchronized void a() {
            }       
            public void b() {
                synchronized(this) {
                }
            }
         }

例如:Thread_1和Thread_2分别是调用方法ab 因此,线程之一将等待其他线程。 Thread_3调用方法ab ,它将按照前面的语句等待。

.class / Synchronized静态方法的同步块

  • 互斥锁将应用于该Class的class对象。
  • Mutext将在所有静态方法之间共享。

      public class Test {    
            public static  synchronized void a() {
            }       
            public static void b() {
                synchronized(Test.class) {
                }
            }
         }

线程_1和线程_2分别是调用方法ab 因此,线程之一将等待其他线程。 Thread_3调用方法ab将按照前面的语句等待。在此类的所有对象和静态引用中,那些静态方法的互斥量相同。

注意:同步实例方法将在对象级别具有互斥体。 因此,它不会影响上述条件。

具有instance reference/object同步块。

  • Mutex将应用于实例级别的用户定义对象。
  • 一个互斥对象将使用一种或多种实例方法。

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调用ca 它将等待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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM