java - 多线程环境中具有静态引用/对象的同步块(synchronized block)

标签 java multithreading concurrency static synchronization

虽然这个问题可能会在SO上被问几次(主要以 this 与 Synchronized block 中的 Bar.clas 的形式),但我不清楚类的静态引用/对象的同步(第三个示例) )这个问题。请看下面的 Java 示例:

  1. 示例#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获取),然后t2t3将处于阻塞状态,但同时其他线程t4 , t5t6允许同时执行。

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

    }

    问题:

    1. 使用 static 会产生什么效果? synchronized 中的引用/对象 block (如示例#3)

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

    3. 静态引用 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++。现在可能会发生很多情况。

    1. 如果在执行 Num++ 之前另一个线程被阻塞,则该线程将保持阻塞状态,直到 t1 退出同步块(synchronized block)。
    2. 如果线程没有被阻塞(比如 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/

    相关文章:

    java - 如何在屏幕旋转时保存 ArrayList<Uri>?

    java - EL 中的方法调用

    c++ - Qt线程同步设计

    python - 如何在 Python 中可用的不同并发方法之间进行选择?

    java - 同时启动多个线程

    java - Java中的有限生成流-如何创建一个?

    Java断言相同的值但出错

    java - 来自单线程执行器的 RejectedExecutionException

    c++ - 在阻塞模式下使用 TServerSocket 时如何处理异常?

    c# - 内存模型和线程池