Java 如果可以通过任何其他方法访问同步块中的对象,那么对该对象进行锁定有什么用?
如果有一个同步块正在锁定一个对象,比如StringBuilder sb,哪个线程正在执行这个同步块,其中sb被锁定,假设有另一个线程正在调用另一个方法,该方法将尝试更改sb的值(不在同步块中),那么,是否允许它这样做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)
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为静态将如何阻止它在不同的线程上访问。我已经尝试过了,但仍然得到相同的输出。所以,锁定一个对象没有什么关系,那么,阻止它锁定任何其他线程?如果我想在任何对象上有一个锁,这样每次只有一个线程可以访问它,我应该使用原子变量吗?还有其他方法可以做到这一点吗?