在阅读" 实践中的Java并发 "和" 实践中的OSGI "后,我发现了一个非常有趣的特定主题; 安全出版.以下内容来自JCIP:
要安全地发布对象,必须同时使对象的引用和对象的状态对其他线程可见.正确构造的对象可以通过以下方式安全发布:
- 从静态初始化程序初始化对象引用.
- 将对它的引用存储到volatile字段中.
- 将对它的引用存储到最终字段中.
- 将对它的引用存储到由(同步)锁定正确保护的字段中.
我的第一个问题:有多少java开发人员知道这个(问题)?有多少真实世界的Java应用程序真正遵循这个,这真的是一个真正的问题吗?我有一种感觉,99%的已实现的JVM不是那种"邪恶",即一个线程不能保证(事实上它实际上(几乎)"不可能")看到陈旧数据只是因为引用不遵循上面的"安全出版成语".
我正在开发一个项目,我需要对我正在运行的服务器进行HTTP URL调用,该服务器Restful Service将响应作为JSON字符串返回.
下面是我使用的主要代码future和callables-
public class TimeoutThreadExample {
private ExecutorService executor = Executors.newFixedThreadPool(10);
public String getData() {
Future<String> future = executor.submit(new Task());
String response = null;
try {
response = future.get(100, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return response;
}
}
Run Code Online (Sandbox Code Playgroud)
下面是我的Task类实现Callable接口并使用RestTemplate...
class Task implements Callable<String> {
private RestTemplate restTemplate = new RestTemplate();
public …Run Code Online (Sandbox Code Playgroud) 如果我决定使用非线程安全的集合并同步其访问权限,我是否需要同步构造函数中的任何变异?例如,在下面的代码中,我理解列表的引用对于构造后的所有线程都是可见的,因为它是最终的.但我不知道这是否构成安全发布,因为构造函数中的add不是同步的,而是在ArrayList的elementData数组中添加一个引用,这是非final的.
private final List<Object> list;
public ListInConstructor()
{
list = new ArrayList<>();
// synchronize here?
list.add(new Object());
}
public void mutate()
{
synchronized (list)
{
if (list.checkSomething())
{
list.mutateSomething();
}
}
}
Run Code Online (Sandbox Code Playgroud) 我对JVM内部的了解是,如果引用未正确发布,则不同的线程可能会看到相同字段的不同值.
我的问题是:Spring bean容器能保证安全发布吗?如果没有,我应该制作所有的bean吸气剂和制定者synchronized还是使用volatile?或者也许使用final字段和构造函数初始化?
我认为这可能只是单例bean的一个问题,因为原型bean是根据请求线程创建的.我的理解是否正确?
我在我的代码中使用Java Callable Future.下面是我使用未来和callables的主要代码 -
public class TimeoutThread {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
Future<String> future = executor.submit(new Task());
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
Run Code Online (Sandbox Code Playgroud)
下面是我的Task类,它实现了Callable接口,我需要根据我们拥有的主机名生成URL,然后使用调用SERVERS RestTemplate.如果第一个主机名中有任何异常,那么我将为另一个主机名生成URL,我将尝试拨打电话.
class Task implements Callable<String> {
private static RestTemplate restTemplate = new RestTemplate();
@Override
public String call() throws Exception {
//.. some code
for(String hostname : hostnames) {
if(hostname == null) {
continue;
}
try …Run Code Online (Sandbox Code Playgroud) 我有@Service几个方法,每个方法使用不同的 web api。每个调用都应该有一个自定义的读取超时。拥有一个 RestTemplate 实例并在每个方法中通过工厂更改超时是否是线程安全的
((HttpComponentsClientHttpRequestFactory)restTemplate.getRequestFactory())
.setReadTimeout(customMillis);
Run Code Online (Sandbox Code Playgroud)
我担心的是我正在更改工厂的超时时间,它不像RequestConfig. 考虑到这些方法可能同时被多个用户调用,这种方法是否是线程安全的?或者每个方法都应该有自己的RestTemplate?
我目前正在处理代码,其中有一个单例,它被许多线程使用,并且没有状态,除了TransactionTemplate和SimpleJdbcTemplate的两个字段,它们在单例函数中用于访问数据库.
这是安全还是我应该在需要的时候创建一个新模板?