简体   繁体   English

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

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

If there is a synchronized block which is taking lock on an object, say StringBuilder sb, which one thread is executing this synchronized block in which sb is locked, suppose there is another thread which is calling another method which will try to change the value of sb(not in synchronized block), then, will it be allowed to do that? 如果有一个同步块正在锁定某个对象,例如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();}
    }
}

}

I thought locking an object would not allow to change that object as well from being modified or accessed. 我认为锁定对象将不允许更改该对象以及被修改或访问。 But, from output I am seeing the locked object can be modified: 但是,从输出中我看到可以修改锁定的对象:

OUTPUT: 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

I am not getting this, can anybody please explain this. 我没有得到这个,任何人都可以解释一下。 What is the use of taking a lock on an object? 锁定对象有什么用? Is it just because wait/notify/notifyAll methods? 仅仅是因为wait / notify / notifyAll方法吗?

If there is a synchronized block which is taking lock on an object, say StringBuilder sb, which one thread is executing this synchronized block in which sb is locked, suppose there is another thread which is calling another method which will try to change the value of sb(not in synchronized block), then, will it be allowed to do that? 如果有一个同步块正在锁定某个对象,例如StringBuilder sb,一个线程正在执行此同步块,其中sb被锁定,则假定另一个线程正在调用另一个方法,该方法将尝试更改sb的值。 sb(不在同步块中),那么将被允许这样做吗?

Uh yes. 嗯是的 I think you need to do some reading about what synchronized does. 我认为您需要阅读有关synchronized功能的内容。 See the Java tutorial . 请参阅Java教程 It does not "lock" an object as in restrict other threads from operating on it. 它不会像限制其他线程对其操作那样“锁定”对象。 What it does is provide mutex for the surrounded block of code for threads that lock on the same object instance . 它的作用是为锁定在同一对象实例上的线程的包围的代码块提供互斥体。 The fields in an object are perfectly able to be mutated both inside or outside the synchronized block. 一个对象中的字段完全可以在synchronized块内部或外部进行突变。

It is always a good idea to synchronize on a constant object so I tend to do something like: 常量对象上进行同步始终是一个好主意,因此我倾向于执行以下操作:

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

If multiple threads are accessing some sort of thread-unsafe object, I will synchronize on that object and do the operations on the object inside the synchronized block: 如果多个线程正在访问某种线程不安全的对象,则将在该对象上进行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

I thought locking an object would not allow to change that object as well from being modified or accessed. 我认为锁定对象将不允许更改该对象以及被修改或访问。 But, from output I am seeing the locked object can be modified: 但是,从输出中我看到可以修改锁定的对象:

No, there is no implicit blocking of the object being changed. 不,没有隐式阻止更改的对象。 If you only access the object's fields inside of the synchronized block then you would have accomplished what you want. 如果仅访问synchronized内部的对象字段,则将完成所需的操作。

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

Right, since you are not inside of a synchronized (abc) block here, there is nothing that stops the thread from calling abc.append(...) . 正确,因为您不在此处的synchronized (abc)块内,所以没有什么可以阻止线程调用abc.append(...)

I am not getting this, can anybody please explain this. 我没有得到这个,任何人都可以解释一下。 What is the use of taking a lock on an object? 锁定对象有什么用? Is it just because wait/notify/notifyAll methods? 仅仅是因为wait / notify / notifyAll方法吗?

Synchronization allows you to control access to a block of code to one thread at a time based on the lock object (or the monitor on that object to be precise). 通过同步,您可以基于锁定对象(或确切地说是该对象上的监视器)控制对一个线程一次代码块的访问。 It also allows you to do lock.wait(...) and lock.notify(...) to control the threads operation and block/release them as well. 它还允许您执行lock.wait(...)lock.notify(...)来控制线程操作以及阻止/释放它们。

Synchronization also puts up memory barriers so that a thread will see changes stored to central memory when it enters a synchronized block and will see it's changes written to central memory when it leaves. 同步还会增加内存壁垒,以便线程在进入synchronized块时将看到存储在中央存储器中的更改,并在线程离开时看到将其更改写入中央存储器中。 Without these memory barriers, if other threads access the StringBuilder without synchronization then they may seem some partially updated portion of that class which can cause NPEs or other failures. 没有这些内存屏障,如果其他线程在不同步的情况下访问StringBuilder ,则它们似乎是该类的部分更新部分,可能导致NPE或其他故障。

A thread will only have to wait to access a locked code region, if that lock is held by another thread. 如果该线程由另一个线程持有,则该线程仅需等待访问锁定的代码区域。 However, it doesn't have to wait if it doesn't need a lock, ie, your StringBuilder instance is only safe if every access is surrounded by a synchronized block locking on the same lock. 但是,它不需要等待是否不需要锁,即,只有在每次访问都被锁定在同一锁上的synchronized块包围着时, StringBuilder实例才是安全的。

In your case, since access to abc in method m2() is not in synchronized block, a thread doesn't need a lock, and hence can access it. 在您的情况下,由于对方法m2() abc访问不在同步块中,因此线程不需要锁,因此可以访问它。

When you are synchronizing on a Lock object the lock object has to be accessible by all threads, so either use a static object or a field belonging to the calling code. Lock object上同步时,所有线程都必须可以访问Lock object ,因此请使用static object或属于调用代码的field

Then you code will work to have only only one thread at a time accessing a certain block(s) of code. 这样,您的代码将只能一次仅访问一个线程来访问特定的代码块。 It will not prevent you acting in that code in anyway that you wish, but only one Thread can do it at one time. 它不会阻止您以您希望的任何方式执行该代码,但是一次只能有一个线程可以执行该操作。

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

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