Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果可以通过任何其他方法访问同步块中的对象,那么对该对象进行锁定有什么用?_Java_Multithreading_Object_Locking_Synchronized - Fatal编程技术网

Java 如果可以通过任何其他方法访问同步块中的对象,那么对该对象进行锁定有什么用?

Java 如果可以通过任何其他方法访问同步块中的对象,那么对该对象进行锁定有什么用?,java,multithreading,object,locking,synchronized,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)

如果有一个同步块正在锁定一个对象,比如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方法吗?

如果锁定被另一个线程持有,那么线程只需等待访问锁定的代码区域。但是,如果不需要锁,则不必等待,也就是说,
StringBuilder
实例只有在每个访问都被同一锁上的
synchronized
块锁定包围时才是安全的


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

锁对象上同步时,所有线程都必须访问锁对象,因此,可以使用属于调用代码的
静态对象
字段

然后,您的代码一次只能有一个线程访问特定的代码块。它不会阻止您按照自己的意愿在代码中执行操作,但一次只能有一个线程执行

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

}
嗯,对。我认为您需要阅读一下
synchronized
的功能。看。它不会像限制其他线程在对象上操作那样“锁定”对象。它所做的是为锁定在同一对象实例上的线程的代码块提供互斥锁。对象中的字段完全可以在
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(…)
来控制线程操作并阻止/释放它们


同步还设置了内存屏障,这样线程在进入
同步的
块时会看到存储到中央内存的更改,在离开时会看到写入中央内存的更改。如果没有这些内存障碍,如果其他线程在没有同步的情况下访问
StringBuilder
,那么它们可能看起来是该类的某些部分更新,这可能会导致NPE或其他故障。

我认为abc是一个字段,我不明白使abc为静态将如何阻止它在不同的线程上访问。我已经尝试过了,但仍然得到相同的输出。所以,锁定一个对象没有什么关系,那么,阻止它锁定任何其他线程?如果我想在任何对象上有一个锁,这样每次只有一个线程可以访问它,我应该使用原子变量吗?还有其他方法可以做到这一点吗?