在多线程环境中使用静态引用/对象的synchronized块

时间:2014-12-19 07:28:46

标签: java multithreading concurrency static synchronization

虽然可能会在SO上多次询问此问题(主要是在同步块中以thisBar.clas的形式),但我不清楚静态参考/对象的同步这个问题的类(第3个例子)。请看下面的Java示例:

  1. 示例#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();
    
    }
    

    }

  2. 结果:来自t1,t2,t3的任何帖子通过已同步的块获取锁定(比如t1获取),然后t2t3将是在阻止状态,但同时允许其他线程t4t5t6执行并发

    1. 示例#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();
      
          }
      }
      
    2. 结果Bar类的任何实例中只有一个线程将获得锁定(比如t1获取锁定)和所有其他线程(t2,t3...t6)将被阻止,直到t1释放锁定。

      1. 示例#3 - synchronized阻止static 参考 / 对象
      2. 公共类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. static块中使用synchronized引用/对象会产生什么影响(如示例#3

        2. synchronized阻止中使用非静态引用/对象会产生什么影响。

        3. 同步块(NUM)中的静态参考synchronized(NUM)是否等同于synchronized(Bar.class)

3 个答案:

答案 0 :(得分:2)

在synchronized块中使用静态引用/对象会产生什么影响(如例#3)

静态对象在线程之间共享,因此当一个线程获取锁时将阻塞所有线程。  意思是如果t1在同步块内,则t2,t3,...,t6被阻止。

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

  1. 如果在执行Num ++之前另一个线程被阻塞,则该线程将保持阻塞状态,直到t1退出同步块。
  2. 如果一个线程没有被阻塞(比如t2)并且num ++被t1执行,那么t2将不会阻塞,因为Num现在是一个新的Integer。因此锁是不同的 并且t2进入获取新整数的锁的块。
  3. 所有主题都可能发生同样的情况。 实际上,可以同时拥有同步块中的所有线程。

    在同步块中使用非静态引用/对象会产生什么影响。

    假设在类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 /同步实例方法

的同步块
  • 互斥锁将应用于当前对象。
  • Mutext将在所有实例方法
  • 中共享

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

例如:Thread_1& Thread_2分别是调用方法ab。所以任何一个线程都会等待其他人。 Thread_3调用方法ab它将按照之前的语句等待。

使用.class /同步静态方法

的同步块
  • 互斥锁将应用于该类的类对象。
  • Mutext将在所有静态方法
  • 中共享

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

Thread_1& Thread_2分别是调用方法ab。所以任何一个线程都会等待其他人。 Thread_3调用方法ab它将按照之前的语句等待。该类的所有对象和静态引用对于那些静态方法具有相同的互斥锁。

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

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调用ca。它将等待Thread_1完成。所以我们可以在实例级别的每个方法中定义锁。

static reference/object的同步阻止。

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

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将获得锁定。其他人会等 因为它的班级水平。