我在这里阅读Java教程中的同步方法/语句:https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
这是有道理的,但是一旦我开始编码,我就陷入了两难境地:我如何处理对象访问自己的字段?
考虑这个例子:
public class MyClass extends Thread {
private PrintWriter printWriter;
public synchronized void setPrintWriter(PrintWriter pw){
printWriter = pw;
}
public synchronized PrintWriter getPrintWriter(){
return printWriter;
}
@Override
public void run() {
PrintWriter pw = getPrintWriter();
while (!this.isInterrupted()) {
try {
pw.println("some stuff");
pw.flush();
Thread.sleep(1000);
}
catch (InterruptedException e){
//pass the interrupt along (will terminate the loop)
Thread.currentThread().interrupt();
}
}
//finish by printing this when we've received an interrupt
pw.println("some more stuff");
}
}
这会有效,但是当我可以直接使用pw
时,使用getter获取副本printWriter
似乎有点荒谬。但我不确定在这种情况下是否有必要,或者在其他情况下是否与此相似。也许它可以保护我免受腐败,如果其他一些线程在我使用printWriter的同时调用了setPrintWriter?
答案 0 :(得分:1)
问题不在于“对象访问自己的字段”。调用方法的任何其他类也(间接)访问字段。
问题是,“如果很多线程访问该类的给定实例,那么它是否安全?”
在您的班级中,如果主题A和B使用您班级的给定实例,则他们都可以访问printWriter
字段。如果在没有正确同步的情况下完成此操作,可能会发生错误(值缓存,数据损坏等)
确保正确的线程安全的最简单方法是遵循以下配方:
synchronized
关键字),锁定(在java.util.concurrent.locks
),原子类(AtomicInteger
...)等。你有很多选择。在这方面,您在此处正确实现了同步:所有printWriter
路径均由synchronized
覆盖(在写入和读取模式下),因此您需要好。