Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.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_Synchronized - Fatal编程技术网

Java 具有外部引用的代码块上的线程安全性

Java 具有外部引用的代码块上的线程安全性,java,synchronized,Java,Synchronized,我对线程安全性有疑问。同步块内的以下代码对当前对象的类变量引用具有外部方法调用(httpClient.execute())。此外部调用是否导致线程安全问题?如果是,如何解决 公共类密钥客户端{ 私有最终HttpClient HttpClient; 公钥{ 已同步(此){ 如果(path.get(“fileName”).toFile()存在()){ if(file==null){ 文件=新文件(“文件名”); } }否则{ HttpResponse response=httpClient.exec

我对线程安全性有疑问。同步块内的以下代码对当前对象的类变量引用具有外部方法调用(httpClient.execute())。此外部调用是否导致线程安全问题?如果是,如何解决

公共类密钥客户端{
私有最终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实例:即使它被标记为
    final
    KeyClient应该负责在构造函数中创建HttpClient。您不应该与任何其他类共享HttpClient实例。此外,检查您在JavaDoc中共享的每个类的每个方法的线程安全性也是一个很好的经验法则

  • 带有
    “fileName”
    的文件也应被视为共享资源,因此请注意,另一个线程可能会同时写入同一文件,这会弄乱您的数据。确保每个线程同时写入自己的文件。一种好的方法是在写入文件时动态生成唯一的文件名前缀。例如,它可以是
    线程ID进程ID时间戳fileName.txt

    • 同步(this)语句确保当一个线程已经进入后续块时,其他线程不会进入该块。从这个角度来看,代码是线程安全的

      但是,没有任何东西可以防止
      httpClient
      被另一个线程调用的
      KeyClient
      类上的另一个非同步方法使用


      最后,在同步无法控制的代码时,总是有可能引入死锁:应该
      httpClient.execute()
      在某个点调用您的代码,然后通过一系列复杂的依赖关系尝试在
      KeyClient
      上获取监视器。就目前情况而言,这不是一个问题。然而,这类问题往往会在代码发展之后引入,因此值得尽早考虑

      您在哪里初始化了httpClient?它位于构造函数
      java公钥客户端(httpClient-httpClient){this.httpClient=httpClient;}
      要求在整个应用程序中保留单个文件,所有对getKey方法的调用都应从同一个文件读取。如果文件不存在,它应该从服务器获取并本地存储在同一个文件中。在这种情况下,请确保仅从一个线程写入文件。这就是它位于同步块内的原因。文件编辑和读取在此块中进行。