繁体   English   中英

如果可以通过任何其他方法访问同步块中的对象,则有什么用?

[英]What is the use of taking a lock on an object in synchronized block, if it can be accessed in any other method?

如果有一个同步块正在锁定某个对象,例如StringBuilder sb,一个线程正在执行此同步块,其中sb被锁定,则假定另一个线程正在调用另一个方法,该方法将尝试更改sb的值。 sb(不在同步块中),那么将被允许这样做吗?

public static void main(String[] args) {
    A a = new A();
    new Thread(new MyRunnable(a), "T1").start();
    new Thread(new MyRunnable(a), "T2").start();
}

static class MyRunnable implements Runnable {
    A a;

    public MyRunnable(A a) {
        super();
        this.a = a;
    }

    @Override
    public void run() {
        while (true) {
            if ("T1".equals(Thread.currentThread().getName())) {
                a.m1();
            } else {
                    a.m2();
            }
        }
    }
}


static class A {

     StringBuilder abc = new StringBuilder("fdfd");

    public void m1() {

        synchronized (abc)
        {

            System.out.println("abc locked : " + abc);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();}
        System.out.println("abc released: " + abc);
        }

    }

    public void m2() {
        System.out
                .println(Thread.currentThread().getName() + "    running");

        System.out.println("trying to access abc");
        abc.append("A");
        System.out.println("abc accessed");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();}
    }
}

}

我认为锁定对象将不允许更改该对象以及被修改或访问。 但是,从输出中我看到可以修改锁定的对象:

OUTPUT:

    abc locked : fdfd
    T2    running
    trying to access abc
    abc accessed
    T2    running
    trying to access abc
    abc accessed
    T2    running
    trying to access abc
    abc released: fdfdAA
    abc accessed
    abc locked : fdfdAAA
    T2    running

我没有得到这个,任何人都可以解释一下。 锁定对象有什么用? 仅仅是因为wait / notify / notifyAll方法吗?

如果有一个同步块正在锁定某个对象,例如StringBuilder sb,一个线程正在执行此同步块,其中sb被锁定,则假定另一个线程正在调用另一个方法,该方法将尝试更改sb的值。 sb(不在同步块中),那么将被允许这样做吗?

嗯是的 我认为您需要阅读有关synchronized功能的内容。 请参阅Java教程 它不会像限制其他线程对其操作那样“锁定”对象。 它的作用是为锁定在同一对象实例上的线程的包围的代码块提供互斥体。 一个对象中的字段完全可以在synchronized块内部或外部进行突变。

常量对象上进行同步始终是一个好主意,因此我倾向于执行以下操作:

 private final Object lock = new Object();
 ...
 synchronized (lock) {
    // only one thread allowed inside this block at a time
 }

如果多个线程正在访问某种线程不安全的对象,则将在该对象上进行synchronized并对synchronized块内的对象执行操作:

 private final SomeUnsafeObject someObject = ...;
 ...
 synchronized (someObject) {
    // only one thread allowed inside this block at a time
    someObject.someUnsafeMethodCall(...);
 }
 // no accesses (read or write) outside of the synchronized block

我认为锁定对象将不允许更改该对象以及被修改或访问。 但是,从输出中我看到可以修改锁定的对象:

不,没有隐式阻止更改的对象。 如果仅访问synchronized内部的对象字段,则将完成所需的操作。

public void m2() {
    ...
    abc.append("A");

正确,因为您不在此处的synchronized (abc)块内,所以没有什么可以阻止线程调用abc.append(...)

我没有得到这个,任何人都可以解释一下。 锁定对象有什么用? 仅仅是因为wait / notify / notifyAll方法吗?

通过同步,您可以基于锁定对象(或确切地说是该对象上的监视器)控制对一个线程一次代码块的访问。 它还允许您执行lock.wait(...)lock.notify(...)来控制线程操作以及阻止/释放它们。

同步还会增加内存壁垒,以便线程在进入synchronized块时将看到存储在中央存储器中的更改,并在线程离开时看到将其更改写入中央存储器中。 没有这些内存屏障,如果其他线程在不同步的情况下访问StringBuilder ,则它们似乎是该类的部分更新部分,可能导致NPE或其他故障。

如果该线程由另一个线程持有,则该线程仅需等待访问锁定的代码区域。 但是,它不需要等待是否不需要锁,即,只有在每次访问都被锁定在同一锁上的synchronized块包围着时, StringBuilder实例才是安全的。

在您的情况下,由于对方法m2() abc访问不在同步块中,因此线程不需要锁,因此可以访问它。

Lock object上同步时,所有线程都必须可以访问Lock object ,因此请使用static object或属于调用代码的field

这样,您的代码将只能一次仅访问一个线程来访问特定的代码块。 它不会阻止您以您希望的任何方式执行该代码,但是一次只能有一个线程可以执行该操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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