在地图中保持当前运行的线程实例?

时间:2013-10-15 07:24:23

标签: java multithreading spring java-ee

我正在使用spring和java。我有以下配置。

的applicationContext.xml

<bean id="taskExecutor"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="5" />
        <property name="maxPoolSize" value="10" />
        <property name="waitForTasksToCompleteOnShutdown" value="true" />
    </bean>

PrintTask.java

public class PrintTask implements Runnable{

    String name;

    public PrintTask(String name){
        this.name = name;
    }

    @Override
    public void run() {
        Map<String, String> map = new HashMap<String, String>();
        map.put(name + " is running", name + " is running");
        Container.containerMap.put(this, map);
        System.out.println(name + " is running");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(name + " is running");
    }

}

PrintTaskTest.java

public class PrintTaskTest {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
        ThreadPoolTaskExecutor taskExecutor = (ThreadPoolTaskExecutor) context.getBean("taskExecutor");
        taskExecutor.execute(new PrintTask("Thread 1"));
        taskExecutor.execute(new PrintTask("Thread 2"));
        taskExecutor.execute(new PrintTask("Thread 3"));
        taskExecutor.execute(new PrintTask("Thread 4"));
        taskExecutor.execute(new PrintTask("Thread 5"));

        //check active thread, if zero then shut down the thread pool
        for (;;) {
            int count = taskExecutor.getActiveCount();
            System.out.println("Active Threads : " + count);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 0) {
                taskExecutor.shutdown();
                break;
            }
        }

        }
}

container.java

public class Container {

    public static Map<PrintTask, Map<String,String>> containerMap = new HashMap<PrintTask, Map<String,String>>();

}

我的要求是:

我有几个线程调用相同的逻辑。在我的示例中,PrintTask由5个线程调用。无论何时调用逻辑,我都必须将值存储在映射中作为键值对。

Key = current Theread object
value = some Map

再次需要时,我可以传递当前线程并从地图中获取其值。

我做得对吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

public class Container {
    private final static Map<PrintTask, Map<String, String>> values = new HashMap<>();

    public static void putTaskToMap(PrintTask key, Map<String, String> values) {
        synchronized(values) {
            values.put(key, values);
        }
    }

    public static Map<String, String> getValues(PrintTask key) {
        syncronized (values) {
        Map<String, String> retVal = values.get(key);
        if(retVal == null) {
             retVal = Collections.synchronizedMap(new HashMap<String, String>());
             values.put(retVal);
        }
        return retVal;
        }
    }
}

public class PrintTask extends Runnable {
@Override
public void run() {
    Map<String, String> map = Container.getValues(this);
    map.put(name + " is running", name + " is running");
    System.out.println(name + " is running");

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(name + " is running");
}

public void someOtherMethod() {
    Map<String, String> values = Container.getValues(this);
    // the values here will always be the _same_ Map containing the same contents as the one in run.
}

重要的部分是:

  1. 您的Map方法之外的run
  2. 你的Map不是实例绑定的(要么是static,要么通过另一个类的共享实例访问)
  3. Map的每次访问均为synchronized。 (通过在方法头中使用Collections.synchronizedMapsynchronized关键字。)
  4. 仔细阅读文档:

    1. synchronized
    2. Collections.synchronizedMap()

答案 1 :(得分:1)

根据您的要求,线程数要执行相同的逻辑,即PrintTask。那么有什么需要将PrintTask作为一个线程,为什么它不能是一个简单的类(单例)并将它传递给那些线程。并使用Lock或synchronized方法使PrintTask线程安全。所以你的PrintTask应该是这样的。

class PrintTask {
    private Map map = Collections.synchronizedMap(new HashMap());
    public synchronized void methodToBeExecutedByThread(String key, Map value) {
        map.put(key, value);
    }
    public Map getMap() {
        return map;
    }
} 


class PrintTaskThread {
    private PrintTask task;
    private String name;
    public PrintTaskThread(PrintTask task, String name) { 
        this.task = task;
        this.name = name;
    }
    public void run() {
        Map map = Collections.synchronizedMap(new HashMap());
        //populate map as requires
        task.methodToBeExecutedByThread(name, map);
    }
}

我建议不要使用Thread / Runnable作为地图的关键。而是在您的案例中创建线程时给出唯一键,线程名称将完成该任务。因此,如果您想要访问名称为“线程1”的线程正在使用的地图。您可以通过<Object of PrintTask>.getMap().get("Thread 1")访问它。