如何在多线程应用程序中使用ConcurrentHashMap与Callable。

huangapple go评论88阅读模式
英文:

How to use ConcurrentHashMap in a MultiThread application with Callable

问题

我想创建一个多线程应用程序,并使用Callable接口,但我希望所有线程同时在ConcurrentHashMap中添加一些值,并在程序结束时打印带有结果的哈希映射。
更具体地说,我有一个包含一些名称的列表。我遍历列表并结合线程,对于每个线程,如果名称的长度小于5,则希望将其添加到并发哈希映射中。
在程序结束时,我希望打印所有名称长度小于5的并发哈希映射。

所以我的主类如下:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AddElementsToMap {

    public static void main(String[] args) {
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();

        List<String> list = new ArrayList<String>();

        list.add("Dimitrios");
        list.add("Maria");
        list.add("Jason");
        list.add("Io");
        list.add("Jessica");

        ExecutorService executor = Executors.newFixedThreadPool(3);
        ArrayList<Future<Object>> futureList = new ArrayList<Future<Object>>();

        for (String name : list) {

            Future future = executor.submit(new AddElementsToMapCallable(name, map));
            futureList.add(future);

        }

        executor.shutdown();

        System.out.println("MAP " + map);

    }

}

和我的Callable如下:

import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

public class AddElementsToMapCallable implements Callable {

    private String name;
    private String className;
    ConcurrentHashMap<String, String> map;

    public AddElementsToMapCallable(String name, ConcurrentHashMap<String, String> map) {

        this.className = this.getClass().getSimpleName();
        this.name = name;
        this.map = map;
    }

    @Override
    public Object call() throws Exception {
        System.out.println(
                className + "call" + " ThreadID = " + Thread.currentThread().getId() + " Processing User = " + name);
        if (name.length() <= 5) {
            System.out.println(className + "call" + " ThreadID = " + Thread.currentThread().getId()
                    + " Processing User = " + name + "length is smaller than 5. Adding!");

            map.put(name, String.valueOf(name.length()));
        } else {
            System.out.println(className + "call" + " ThreadID = " + Thread.currentThread().getId()
                    + " Processing User = " + name + "length is BIGGER than 5");

        }

        return map;
    }

    public long getThreadId() {
        return Thread.currentThread().getId();
    }

    public Thread getThread() {
        return Thread.currentThread();
    }
}

但是我得到的结果不是我想要的...

MAP {}
AddElementsToMapCallablecall ThreadID = 14 Processing User = Maria
AddElementsToMapCallablecall ThreadID = 13 Processing User = Dimitrios
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jason
AddElementsToMapCallablecall ThreadID = 14 Processing User = Marialength is smaller than 5. Adding!
AddElementsToMapCallablecall ThreadID = 13 Processing User = Dimitrioslength is BIGGER than 5
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jasonlength is smaller than 5. Adding!
AddElementsToMapCallablecall ThreadID = 15 Processing User = Io
AddElementsToMapCallablecall ThreadID = 15 Processing User = Iolength is smaller than 5. Adding!
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jessica
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jessicalength is BIGGER than 5

有人能帮助我吗?我做错了什么?谢谢!

英文:

I want to have a threading application and I use Callable interface, but I want all the threads to add simultaneously in a ConcurrentHashmap some values, and at the end of the program to print the hashmap with the results.
More specifically, I have a list with some names. I iterate through the list and combine threading and in each thread if the name's length is shorter than 5 , then I want it added to the concurrent hashmap.
At the end of the program I want to print the concurrent hashmap with all the names that are shorter than 5.

So my main class is the following:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class AddElementsToMap {
public static void main(String[] args) {
ConcurrentHashMap&lt;String, String&gt; map = new ConcurrentHashMap&lt;String, String&gt;();
List&lt;String&gt; list = new ArrayList&lt;String&gt;();
list.add(&quot;Dimitrios&quot;);
list.add(&quot;Maria&quot;);
list.add(&quot;Jason&quot;);
list.add(&quot;Io&quot;);
list.add(&quot;Jessica&quot;);
ExecutorService executor = Executors.newFixedThreadPool(3);
ArrayList&lt;Future&lt;Object&gt;&gt; futureList = new ArrayList&lt;Future&lt;Object&gt;&gt;();
for (String name : list) {
Future future = executor.submit(new AddElementsToMapCallable(name, map));
futureList.add(future);
}
executor.shutdown();
System.out.println(&quot;MAP &quot; + map);
}
}

and My Callable is the following

import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
public class AddElementsToMapCallable implements Callable {
private String name;
private String className;
ConcurrentHashMap&lt;String, String&gt; map;
public AddElementsToMapCallable(String name, ConcurrentHashMap&lt;String, String&gt; map) {
this.className = this.getClass().getSimpleName();
this.name = name;
this.map = map;
}
@Override
public Object call() throws Exception {
HashMap&lt;String, String&gt; map = new HashMap&lt;String, String&gt;();
System.out.println(
className + &quot;call&quot; + &quot; ThreadID = &quot; + Thread.currentThread().getId() + &quot; Processing User = &quot; + name);
if (name.length() &lt;= 5) {
System.out.println(className + &quot;call&quot; + &quot; ThreadID = &quot; + Thread.currentThread().getId()
+ &quot; Processing User = &quot; + name + &quot;length is smaller than 5. Adding!&quot;);
map.put(name, String.valueOf(name.length()));
} else {
System.out.println(className + &quot;call&quot; + &quot; ThreadID = &quot; + Thread.currentThread().getId()
+ &quot; Processing User = &quot; + name + &quot;length is BIGGER than 5&quot;);
}
return map;
}
public long getThreadId() {
return Thread.currentThread().getId();
}
public Thread getThread() {
return Thread.currentThread();
}
}

but what I get as a result is as you can see not what I wanted...

 MAP {}
AddElementsToMapCallablecall ThreadID = 14 Processing User = Maria
AddElementsToMapCallablecall ThreadID = 13 Processing User = Dimitrios
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jason
AddElementsToMapCallablecall ThreadID = 14 Processing User = Marialength is smaller than 5. Adding!
AddElementsToMapCallablecall ThreadID = 13 Processing User = Dimitrioslength is BIGGER than 5
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jasonlength is smaller than 5. Adding!
AddElementsToMapCallablecall ThreadID = 15 Processing User = Io
AddElementsToMapCallablecall ThreadID = 15 Processing User = Iolength is smaller than 5. Adding!
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jessica
AddElementsToMapCallablecall ThreadID = 15 Processing User = Jessicalength is BIGGER than 5

Could someone help me? What am I doing wrong??
Thanks !

答案1

得分: 1

构造函数中传递的map变量和call方法的第一行存在作用域问题。如果您想将条目添加到构造函数中传递的Map中,可以尝试类似以下的方式:

public class AddElementsToMap {

    public static void main(String[] args) {
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();

        List<String> list = new ArrayList<String>();

        list.add("Dimitrios");
        list.add("Maria");
        list.add("Jason");
        list.add("Io");
        list.add("Jessica");

        ExecutorService executor = Executors.newFixedThreadPool(3);
        ArrayList<Future<Object>> futureList = new ArrayList<Future<Object>>();

        for (String name : list) {

            Future future = executor.submit(new AddElementsToMapCallable(name, map));
            futureList.add(future);

        }

        // Wait until all threads are finished (Hopefully this is just for a learning experience)
        try {
            for (Future f : futureList) {
                f.get();
            }
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace(System.err);
        }

        executor.shutdown();

        System.out.println("MAP " + map);

    }


    static class AddElementsToMapCallable implements Callable {

        private String name;
        private String className;
        ConcurrentHashMap<String, String> map;

        public AddElementsToMapCallable(String name, ConcurrentHashMap<String, String> map) {

            this.className = this.getClass().getSimpleName();
            this.name = name;
            this.map = map;
        }

        @Override
        public Object call() throws Exception {
            // 移除此行。这个map会遮蔽构造函数中传递的map
            System.out.println(
                  className + "call" + " ThreadID = " + Thread.currentThread().getId()
                        + " Processing User = " + name);
            if (name.length() <= 5) {
                System.out.println(
                      className + "call" + " ThreadID = " + Thread.currentThread().getId()
                            + " Processing User = " + name + " length is smaller than 5. Adding!");

                map.put(name, String.valueOf(name.length()));
            } else {
                System.out.println(
                      className + "call" + " ThreadID = " + Thread.currentThread().getId()
                            + " Processing User = " + name + " length is BIGGER than 5");

            }

            return map;
        }

        public long getThreadId() {
            return Thread.currentThread().getId();
        }

        public Thread getThread() {
            return Thread.currentThread();
        }
    }
}
英文:

Scope issue of map variable passed in the constructor and the first line of method call. If you want to add the entries into the Map passed in the constructor you can try something like this:

public class AddElementsToMap {

    public static void main(String[] args) {
        ConcurrentHashMap&lt;String, String&gt; map = new ConcurrentHashMap&lt;String, String&gt;();

        List&lt;String&gt; list = new ArrayList&lt;String&gt;();

        list.add(&quot;Dimitrios&quot;);
        list.add(&quot;Maria&quot;);
        list.add(&quot;Jason&quot;);
        list.add(&quot;Io&quot;);
        list.add(&quot;Jessica&quot;);

        ExecutorService executor = Executors.newFixedThreadPool(3);
        ArrayList&lt;Future&lt;Object&gt;&gt; futureList = new ArrayList&lt;Future&lt;Object&gt;&gt;();

        for (String name : list) {

            Future future = executor.submit(new AddElementsToMapCallable(name, map));
            futureList.add(future);

        }

        // Wait until all threads are finished (Hopefully this is jsut for a learning experience)
        try {
            for (Future f : futureList) {
                f.get();
            }
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace(System.err);
        }

        executor.shutdown();

        System.out.println(&quot;MAP &quot; + map);

    }


    static class AddElementsToMapCallable implements Callable {

        private String name;
        private String className;
        ConcurrentHashMap&lt;String, String&gt; map;

        public AddElementsToMapCallable(String name, ConcurrentHashMap&lt;String, String&gt; map) {

            this.className = this.getClass().getSimpleName();
            this.name = name;
            this.map = map;
        }

        @Override
        public Object call() throws Exception {
            HashMap&lt;String, String&gt; map = new HashMap&lt;String, String&gt;(); // REMOVE this line. This map will shadow the map passed in the constructor
            
            System.out.println(
                  className + &quot;call&quot; + &quot; ThreadID = &quot; + Thread.currentThread().getId()
                        + &quot; Processing User = &quot; + name);
            if (name.length() &lt;= 5) {
                System.out.println(
                      className + &quot;call&quot; + &quot; ThreadID = &quot; + Thread.currentThread().getId()
                            + &quot; Processing User = &quot; + name + &quot;length is smaller than 5. Adding!&quot;);

                map.put(name, String.valueOf(name.length()));
            } else {
                System.out.println(
                      className + &quot;call&quot; + &quot; ThreadID = &quot; + Thread.currentThread().getId()
                            + &quot; Processing User = &quot; + name + &quot;length is BIGGER than 5&quot;);

            }

            return map;
        }

        public long getThreadId() {
            return Thread.currentThread().getId();
        }

        public Thread getThread() {
            return Thread.currentThread();
        }
    }
}

huangapple
  • 本文由 发表于 2023年6月8日 16:08:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429845.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定