Java 我可以初始化静态成员一次并跨线程共享它吗?
这是我第一次尝试编写一个使用多线程的程序,因此我有几个关于在程序中使用并发的问题 我的程序从web UI获取用户输入,然后使用该用户输入启动一个进程。我知道我必须利用并发性,因为这个过程需要一个小时以上,而且我不可能让用户在开始下一个过程之前等待一个过程完成 下面的简化代码处理用户输入,然后启动流程Java 我可以初始化静态成员一次并跨线程共享它吗?,java,multithreading,concurrency,static,Java,Multithreading,Concurrency,Static,这是我第一次尝试编写一个使用多线程的程序,因此我有几个关于在程序中使用并发的问题 我的程序从web UI获取用户输入,然后使用该用户输入启动一个进程。我知道我必须利用并发性,因为这个过程需要一个小时以上,而且我不可能让用户在开始下一个过程之前等待一个过程完成 下面的简化代码处理用户输入,然后启动流程 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletExcep
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String myInput = request.getParameter("input");
Thread t = new Thread(new MyRunnable(myInput));
t.start();
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Process started!");
out.close();
}
下面的代码简化了我的实际过程
public class MyRunnable implements Runnable {
private static HashMap<String,String> mapOfConstants = null;
private String member;
public MyRunnable(String member) {
this.member = member;
}
@Override
public void run() {
if (mapOfConstants == null) init();
// and so on...
}
private void init() {
mapOfConstants = new HashMap<String,String>();
mapOfConstants.put("LOCATION", "http://localhost/folder");
// and so on...
}
}
公共类MyRunnable实现Runnable{
私有静态HashMap mapOfConstants=null;
私有字符串成员;
公共MyRunnable(字符串成员){
this.member=成员;
}
@凌驾
公开募捐{
if(mapOfConstants==null)init();
//等等。。。
}
私有void init(){
mapOfConstants=newHashMap();
常量的映射。放置(“位置”http://localhost/folder");
//等等。。。
}
}
在上面的代码中,我打算将一系列占位符定义为一个常量,它将存储在HashMapmapOfConstants
中
编辑:
最终,我可能希望使这个映射的初始化从其他地方获取值,比如文本文件
“我的代码”是否达到了在
MyRunnable
的所有实例之间共享此占位符映射的目的,只执行一次初始化过程?如果您想在所有用户之间共享常量,那么您的路径是正确的,但是您必须同步您的代码
同步代码的最简单方法是编写
public synchronized void run() {
}
请阅读一些关于Java同步的教程,因为这是Java中的一个雷区,即使是经验丰富的开发人员有时也会遇到问题
关于你的第二个问题:请写一个新问题。我正在回答你的问题1,你应该为第2个问题发布另一个问题
我的代码是否达到共享此占位符地图的目的
在MyRunnable的所有实例中,执行此初始化过程
只有一次
是,但它不是线程安全的。所以你有两个选择:
我的回答假设您不想在任何时候更改地图内容
运行时,正如您所说,它是常量的映射
- 选项1:使映射成为最终映射,并使用集合。不可修改映射
并在静态块中初始化它,这也使代码线程安全
synchronized
块
//keeping map `volatile`
private static volatile HashMap<String,String> mapOfConstants = null;
...
if(map == null)
synchronized(SomeClass.class){
if(map == null){
init();
}
}
//保持map`volatile`
私有静态volatile HashMap mapOfConstants=null;
...
if(map==null)
已同步(SomeClass.class){
if(map==null){
init();
}
}
首先,不要在run()
方法中初始化映射,不能保证初始化只发生一次。当然,在这种情况下,不管你创建了多少次地图,最终一个会被设置为静态参考,其他的会被GCed。只是不太好看。我建议使用静态初始化块:
private final static Map<String,String> mapOfConstants;
static {
Map<String, String> map = new HashMap<String, String>();
// initialize map.
map.put("", "");
...
// convert the map into unmodifiable
mapOfConstants = Collections.unmodifiableMap(map);
}
通过这种方式,您可以针对不同的常量配置编写测试,而无需修改可运行类。是的,您可以初始化静态成员一次,并在线程之间共享它,但前提是您必须格外小心。例如,必须同步所有init()调用站点;也就是说,init()只能从构造函数或同步方法调用。或者,您可以在静态初始值设定项块中初始化mapOfConstants变量。无论您使用哪种方法,您也可以将实现看作是<强> MAPOFMODENT/<强>变量的具体类型,因为这将避免以后出现头痛。 如果不谨慎行事,可能会导致您遇到“双重检查锁定”竞争条件。此外,初始化静态引用变量通常被认为是一种反模式,因为在这种情况下,映射中的条目可以在程序的一次激活中不受限制地增长。通常,这种引用的唯一可接受的用法是,如果内容是恒定的,或者如果内容随着时间的推移增长非常缓慢(以对数为单位)。对数增长可以通过使用a来辅助,否则,可以明智地使用
到目前为止,重点似乎是初始化静态mapOfConstants变量。但这忘记了地图的全部目的(通常)是存储一些东西,以便在最好的情况下在O(1)时间内检索。请记住,当存储和检索操作(在mapOfConstants变量上)跨越线程边界时,这些操作也必须同步。如果没有同步,一个线程的添加或编辑可能会被其他线程错过,这可能会影响程序的数据完整性。我知道这不会收到很好的效果,但您的代码几乎没有问题。尽管不是严格的线程安全(就只加载一次属性而言),但它仍然是正确的(就不创建损坏的数据而言) 最大的变化是:
private void init() {
HashMap<String,String> tempMap = new HashMap<String,String>(); // <--- new object assigned to a placeholder variable
tempMap.put("LOCATION", "http://localhost/folder");
// and so on...
mapOfConstants = Collections.unmodifiableMap(tempMap); // <--- atomic assignment here
}
private void init(){
HashMap tempMap=new HashMap();//对于初学者,您可以使映射成为最终映射,并在声明时对其进行初始化。请不要在一个堆栈溢出问题中要求多个答案。请编辑您的问题以仅包含一个问题
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<String, String> sharedMapOfConstants = MapOfConstantsFactory.getMapOfConstants();
String myInput = request.getParameter("input");
Thread t = new Thread(new MyRunnable(myInput, sharedMapOfConstants));
t.start();
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Process started!");
out.close();
}
private void init() {
HashMap<String,String> tempMap = new HashMap<String,String>(); // <--- new object assigned to a placeholder variable
tempMap.put("LOCATION", "http://localhost/folder");
// and so on...
mapOfConstants = Collections.unmodifiableMap(tempMap); // <--- atomic assignment here
}