首页 文章

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

提问于
浏览
0

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

  • Example#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();

}

}

Result :当来自 t1,t2,t3 的任何线程通过synchronized块获取锁定(比如 t1 acquire),那么 t2t3 将处于 blocked 状态,但同时允许其他线程 t4 ,_ t5t6 执行 concurrently .

  • Example#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();

    }
}

Result :只有 Bar 类的任何实例的一个线程将获得锁定(比如 t1 获取锁定),所有其他线程( t2,t3...t6 )将被阻止,直到 t1 释放锁定 .

  • Example#3 - synchronized 阻止 static Reference / Object

公共类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();

}

}

Question

  • synchronized 块中使用 static reference / object会有什么影响(如 Example#3

  • synchronized 块中使用 non-static reference / object会产生什么影响 .

  • 同步块( synchronized(NUM) )中的静态引用 NUM 是否等同于 synchronized(Bar.class)

3 回答

  • 0

    What would be the effect of using static reference/object in synchronized block (as in Example#3)

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

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

    • 如果在执行Num之前另一个线程被阻塞,则该线程将保持阻塞,直到t1退出同步块 .

    • 如果一个线程没有被阻塞(比如t2)并且Num被t1执行,那么t2将不会阻塞,因为Num现在是一个新的Integer . 因此锁定是不同的,并且t2进入块获取新Integer的锁定 .

    所有线程都可能发生同样的故事 . In fact, it is possible to have all the threads in the synchronized block at the same time.

    What would be the effect of using non-static reference/object in synchronized block.

    假设在类Bar的实例之间不共享非静态对象,因此只有t1,t2,t3的一个线程可以在同步块中 . 类似地,对于t4,t5,t6 . 但是,如果它是共享的,它与静态对象具有相同的效果 .

    Also does the Static reference NUM in synchronized block (synchronized(NUM)) is equivalent to synchronized(Bar.class) ?

    如果您没有像我在第一个问题的答案中解释的那样更改NUM

  • 1

    互斥锁是静态的还是非静态的并不重要,只要它是同一个对象 .

    要回答第一个问题, NUM 对象对于所有线程都是相同的,因此没有两个线程可以同时获取锁定 .

    第二个问题更棘手......如果 synchronized 块中的对象对于所有线程都是相同的,那么它们将像在前一个场景中那样执行 . 如果每个线程都有自己的对象,那么就没有什么能阻止你的所有线程一次进入临界区 .

    此外,请记住,当您调用 t2.start() 时,可能已经完成处理(同样可能发生在您的其他线程中),因此请确保您不会被您在控制台上看到的内容所迷惑...

  • 2

    在回答您的问题之前您需要了解以下几点 .

    以上所有同步在对象或类级别中具有不同级别的互斥锁 .

    What is Mutex

    在Java中,每个对象都只有一个监视器和与之关联的监视器 . 单个监视器有几个门,但每个都由synchronized关键字指示 . 当一个线程通过synchronized关键字时,它会有效地锁定所有门 . 当然,如果一个线程没有锁定门,而其他一些线程在任何时候都是自由驳船 . 资料来源:Click here

    Synchronization block with this/Synchronized Instance Method

    • 互斥锁将应用于当前对象 .

    • Mutext将在所有 instance method 中共享 .

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

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

    Synchronization block with .class/Synchronized static Method

    • Mutex将应用于该类的类对象 .

    • Mutext将在所有 static method 中共享 .

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

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

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

    Synchronization block with 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完成 . 所以我们可以在实例级别的每个方法中定义锁 .

    Synchronization block with 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将获得锁定 . 其他人会等因为它的 class 水平 .

相关问题