Java 具有外部引用的代码块上的线程安全性
我对线程安全性有疑问。同步块内的以下代码对当前对象的类变量引用具有外部方法调用(httpClient.execute())。此外部调用是否导致线程安全问题?如果是,如何解决Java 具有外部引用的代码块上的线程安全性,java,synchronized,Java,Synchronized,我对线程安全性有疑问。同步块内的以下代码对当前对象的类变量引用具有外部方法调用(httpClient.execute())。此外部调用是否导致线程安全问题?如果是,如何解决 公共类密钥客户端{ 私有最终HttpClient HttpClient; 公钥{ 已同步(此){ 如果(path.get(“fileName”).toFile()存在()){ if(file==null){ 文件=新文件(“文件名”); } }否则{ HttpResponse response=httpClient.exec
公共类密钥客户端{
私有最终HttpClient HttpClient;
公钥{
已同步(此){
如果(path.get(“fileName”).toFile()存在()){
if(file==null){
文件=新文件(“文件名”);
}
}否则{
HttpResponse response=httpClient.execute();
Map Map=mapper.readValue(response.getResponseBody(),Map.class);
文件=新文件(“文件名”);
writeValue(文件,映射);
}
}
}
}
公共类HttpClient{
公共HttpResponse execute(){
//一些代码
返回新的HttpResponse(200,“”);
}
}
HTTPClient是最终版
,这意味着它是一个常量变量,初始化后无法更改。因此,这段代码很可能没有任何线程安全问题(当然,除非HTTPClient类中存在不同步的可变变量)
不,不会的
如果调用同步块块中的任何内容也会被锁定。当您进入同步块时,锁定将启用,当您退出该块时,锁定将被禁用
但是,其他线程对执行方法的调用不会被锁定——任何人都可以同时调用它们。只有一个线程可以进入
synchronized
部分,因此您的http客户端实例永远不会被同时使用。另外,synchronized
部分使任何进入/离开线程与其他线程同步其状态,因此http客户端是否具有可变状态并不重要,因为它将被正确同步
因此,代码是线程安全的。您必须注意两种可能的共享资源。它们都会危及线程安全
- KeyClient内部的HttpClient实例:即使它被标记为
,KeyClient应该负责在构造函数中创建HttpClient。您不应该与任何其他类共享HttpClient实例。此外,检查您在JavaDoc中共享的每个类的每个方法的线程安全性也是一个很好的经验法则final
- 带有
的文件也应被视为共享资源,因此请注意,另一个线程可能会同时写入同一文件,这会弄乱您的数据。确保每个线程同时写入自己的文件。一种好的方法是在写入文件时动态生成唯一的文件名前缀。例如,它可以是“fileName”
线程ID进程ID时间戳fileName.txt
- 同步(this)语句确保当一个线程已经进入后续块时,其他线程不会进入该块。从这个角度来看,代码是线程安全的
但是,没有任何东西可以防止
httpClient
被另一个线程调用的KeyClient
类上的另一个非同步方法使用
最后,在同步无法控制的代码时,总是有可能引入死锁:应该
httpClient.execute()
在某个点调用您的代码,然后通过一系列复杂的依赖关系尝试在KeyClient
上获取监视器。就目前情况而言,这不是一个问题。然而,这类问题往往会在代码发展之后引入,因此值得尽早考虑 您在哪里初始化了httpClient?它位于构造函数java公钥客户端(httpClient-httpClient){this.httpClient=httpClient;}
要求在整个应用程序中保留单个文件,所有对getKey方法的调用都应从同一个文件读取。如果文件不存在,它应该从服务器获取并本地存储在同一个文件中。在这种情况下,请确保仅从一个线程写入文件。这就是它位于同步块内的原因。文件编辑和读取在此块中进行。