Java 如何使这个函数线程安全? 公共类Sol{ 静态地图; 静态列表排序规则(列表工作人员){ List res=new ArrayList(); emap=newhashmap(); 适用于(清单e:工人) emap.put(Integer.parseInt(e.get(0)),e); 用于(列出工人:工人) { //接触工人 ..... } 集合。排序(res); 返回res; } 公共静态整数dfs(整数eid){ List employee=emap.get(eid); int工资=0; 字符串ans=employee.get(3); 对于(int i=0;i 防止外部访问emap 初始化emap以排除NPE
例如:Java 如何使这个函数线程安全? 公共类Sol{ 静态地图; 静态列表排序规则(列表工作人员){ List res=new ArrayList(); emap=newhashmap(); 适用于(清单e:工人) emap.put(Integer.parseInt(e.get(0)),e); 用于(列出工人:工人) { //接触工人 ..... } 集合。排序(res); 返回res; } 公共静态整数dfs(整数eid){ List employee=emap.get(eid); int工资=0; 字符串ans=employee.get(3); 对于(int i=0;i 防止外部访问emap 初始化emap以排除NPE,java,Java,例如: public class Sol { static Map<Integer, List<String>> emap; static List<Integer> sortSalaries(List<List<String>> workers) { List<Integer> res = new ArrayList<Integer>(); emap = n
public class Sol {
static Map<Integer, List<String>> emap;
static List<Integer> sortSalaries(List<List<String>> workers) {
List<Integer> res = new ArrayList<Integer>();
emap = new HashMap<>();
for (List<String> e: workers)
emap.put(Integer.parseInt(e.get(0)), e);
for(List<String> worker: workers )
{
//accessing workers
.....
}
Collections.sort(res);
return res;
}
public static int dfs(int eid) {
List<String> employee = emap.get(eid);
int salary=0;
String ans = employee.get(3);
for (int i=0;i<ans.length();i=i+2)
{
// accesing emap
......
}
return salary;
}
}
public-final-class-Sol{
私有静态最终映射emap=newhashmap();
静态列表排序规则(列表工作人员){
已同步(Foo.class){
适用于(清单e:工人)
emap.put(Integer.parseInt(e.get(0)),e);
}
//执行smth,而不是访问emap
}
公共静态同步整数dfs(整数eid){
//使用访问emap执行smth
}
}
在sortSalaries
中,您可以使用for loop
最小化synchoronized
块。在dfs
中,您可以在方法的不同位置访问emap
,因此您必须同步enire方法
使用
ConcurrentHashMap
或Vector
在这里都没有帮助,因为在get/set
元素到集合之间,它们可以被更改,这对于dfs
方法是不合适的:调用它时应该感觉emap
。我在评论中问了你一个问题-你明白为什么吗如果从多个线程调用ese方法,则这些方法不是线程安全的?您向我指出了一个链接,但没有说明您是否真正理解它,以及为什么您认为您的类不是线程安全的,因此我提供了一点背景知识,而不是直接回答这个问题
简短的讨论
当您开始在运行线程/调用线程之间共享数据时,任何类或其方法都可能变得不线程安全。如果线程之间没有共享数据,则默认情况下,您的类是线程安全的。使类线程安全的最简单方法是停止在线程之间共享数据,在您的情况下,它将是rem椭圆的-emap
(因为它是一个类状态,在方法中使用)和列表工作者
(这是我不确定的,因为它是从调用方传递的引用,不同的方法调用将在同一个实例上工作,或者可能是不同的实例被传递到此方法)并用局部变量替换这些方法
方法局部变量在默认情况下是线程安全的,因为每次调用都会创建和销毁新实例
如果您不能这样做或不可行,请按照oleg.cherednik的答案在块级或方法级同步变量-emap
。请记住,Java中有多种方法可以同步,其中synchronized
关键字最简单
现在,对于方法参数-List worker
&int-eid
,不需要对eid
进行同步,因为您只是简单地读取它,而不是更新它&而且它不是按引用传递,而是按值传递,因为类型是原语
如果要将同一个列表实例传递给来自不同线程的此方法调用,则需要同步访问列表工作者。请参阅,oleg.cherednik的回答中遗漏了这一点。您最好判断此引用是否需要同步
很容易假设List
迭代是线程安全的(因为您没有更新列表),但这可能并不总是正确的。有关详细讨论
因此,总结如下-您首先通过分析某些对象是否在线程之间共享来开始为类实现线程安全。如果对象共享,则需要同步对这些对象的读/写(以使其原子化&前提是这些对象尚未是线程安全的)。如果没有共享对象,那么它已经是线程安全的。另外,尝试使用已经是线程安全的数据结构创建类,这样您就可以减少工作量
java.lang.NullPointerException
(NPE)oleg.cherednik回答的要点也站得住脚。这是线程吗?我看不到任何运行
方法?这实际上是线程吗?这些函数是从线程调用的。所以我想确保返回了正确的数据。为什么要使用静态
方法?创建这个类的单个实例对您来说不合适?@mzz:first,你明白为什么从多个线程调用这些方法不是线程安全的吗?我也在sortSalaries中使用res arraylist,所以整个func必须正确同步。你能告诉我为什么不需要更多地使用vector或hashtable吗clearly@mzz:res
是一个方法局部变量,将为每个方法创建一个新实例调用(不共享实例),因此不需要同步。尽管引用被传递给了列表工作者,但工作者仍然是一个局部变量(方法参数是局部变量)它被传递给workers的一个新副本,对吗?所以workers不需要sync,对吗?不,它不是method局部变量&这就是为什么我在其他问题上指向格雷的答案。这需要同步。当线程a调用sortSalaries传递workers的引用时,线程a是否可以更改sortSalaries何时被执行?不,对吗?SORTSALIES必须完成执行,线程A才能恢复执行?@mzz:忘记修改,迭代本身可能不是线程安全的。这取决于你如何在这个方法中同步。这只是一个简单的过程
public final class Sol {
private static final Map<Integer, List<String>> emap = new HashMap<>();
static List<Integer> sortSalaries(List<List<String>> workers) {
synchronized (Foo.class) {
for (List<String> e : workers)
emap.put(Integer.parseInt(e.get(0)), e);
}
// do smth, not access emap
}
public static synchronized int dfs(int eid) {
// do smth with accessing emap
}
}