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

时间:2014-07-10 05:33:54

标签: java multithreading object locking synchronized

如果有一个正在锁定对象的同步块,比如StringBuilder 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();}
    }
}

}

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

输出:

    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方法吗?

3 个答案:

答案 0 :(得分:2)

  

如果有一个正在锁定对象的同步块,比如StringBuilder sb,哪一个线程正在执行这个同步块,其中sb被锁定,假设有另一个线程正在调用另一个尝试更改的方法那么sb的值(不在同步块中)是否允许这样做?

是的,是的。我想你需要阅读synchronized的内容。请参阅Java tutorial。它没有"锁定"限制其他线程对其进行操作的对象。它的作用是为锁定相同对象实例的线程的包围代码块提供互斥锁。对象中的字段完全能够在synchronized块内部或外部进行变异。

常量对象上进行同步总是一个好主意,所以我倾向于做类似的事情:

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

如果多个线程正在访问某种线程不安全的对象,我将在该对象上进行同步并对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或其他故障。

答案 1 :(得分:0)

如果该锁由另一个线程持有,则线程只需等待访问锁定的代码区域。但是,如果它不需要锁定,它就不必等待,即,如果每个访问都被StringBuilder块锁定,则synchronized实例只是安全的。同样的锁。

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

答案 2 :(得分:0)

当您在Lock object上进行同步时,所有线程都必须可以访问锁定对象,因此请使用属于调用代码的static objectfield

然后,您的代码将只能使用一个线程一次访问某些代码块。它不会阻止你以任何方式在你的代码中行事,但只有一个线程可以同时执行。