如何以正确的方式动态处理开始和结束线程和信息?

时间:2017-01-31 23:51:06

标签: java arrays multithreading

我还没有能够找到适合我的问题的答案,希望我能在这里找到一个可以指引我正确方向的人。

我试图让程序动态创建类实例和线程,并处理结束它们,并在允许更多启动之前清除内存。

我写的程序涉及访问大量设备,有时是定期访问。我需要一种适当的方法来跟踪线程,用户命令启动它们,并排队等待它们不会溢出内存。

用户可以选择结束可能包含许多线程的任务,因此我需要能够对该组进行全面删除。

我认为Arraylist是最好的,但是如下所示,我需要3个列表来协同工作,包括名称,类实例和线程。

public Class implements Runnable {

    private inner class doThings implements Runnable {

        public bool active = true

        public bool done(){
                return true;
            } 

        public run() {
            while (active){
            x=1+1
        }
        public void instakill(){
            active = false;
        }
    }

    public void mainLoop() {

        int maxThreads = 50

        List names;
        List instances;
        List threads;

        while true {

            for (each request) {

                if (threads.size < maxThreads ) {

                    names.add("unique name")
                    instances.add(new doThings())
                    threads.add(new Thread(instances.size - 1))

                    threads.get(Threads.size - 1).start

                }               
            }

            for (each instance) {

                if (doThings.done()){

                    int arrayID = instance.getIndex

                    names.remove(arrayID)
                    instances.remove(arrayID)
                    threads.remove(arrayID)

                    trim-All-Lists-To-Size();

                }

            }

        }

因此,主循环将创建类doThings的新实例,以及唯一的名称和运行该类的线程。这些被放入单独的,未链接的阵列中。我匹配它们的唯一方法是通过获取一个数组中的任何索引并计算,因为我从统一的所有数组中添加和对象,它应该是所有的相同索引。有点像填充3杯独立的水,并期望它们处于同一水平。

当然,除非它不是如何发挥作用。

如果我知道如何组合3位信息(名称,实例,线程),我可能不会遇到这个问题吗?

我是否应该将所有内容封装到更大的类中并保留其中的ArrayLists(或CopyOnWriteArrayLists)?

我不确定解决这个问题的正确方法是什么

感谢您的帮助!!

2 个答案:

答案 0 :(得分:0)

正如Peter所建议的那样,你应该明确考虑使用ExecutorService API而不是基于线程管理开发类似的机制。

尽管如此,关于您的原始代码,我认为您的难度实际上与线程管理无关,而只是与Java中的数据结构有关。不是并行维护三个不同的列表,最常见的方法只是将三个信息封装在某个内部类的实例中(例如Entry),然后只有一个这些Entry的列表(也就是说,在现代Java中:List<Entry>)。

另一件需要知道的事情是,除非使用迭代器的remove方法,否则在迭代该集合时,永远不会删除集合中的元素;如果你这样做,你最终会得到ConcurentModificationException。正确的方法是在集合上显式创建迭代器(例如list.iterator())然后迭代它(使用iterator.hasNext()iterator.next()),最后使用`iterator.remove删除元素( )。

例如,您的代码可能如下所示:

public class ParentClass {

    private class RunningInstanceEntry {
        public String name;
        public Worker worker;
        public Thread thread;
    }

    private class Worker implements Runnable {
        public boolean active = true;

        public boolean done() {
            return true;
        } 

        public run() {
            while (active) {
                x = 1+1;
            }
        }

        public void instakill() {
            active = false;
        }
    }

    public void mainLoop() {
        int maxThreads = 50;

        List<RunningInstanceEntry> instances =
                         new ArrayList<RunningInstanceEntry>();

        while (true) {
            for (R request : requests) {
                if (threads.size < maxThreads) {
                    RunningInstanceEntry instance =
                        new RunningInstanceEntry();

                    instance.name = "unique name";
                    instance.worker = new Worker();
                    instance.thread = new Thread(instance.worker);
                    instance.thread.start();

                    instances.add(instance);
                }               
            }

            Iterator<RunningInstanceEntry> iterator =
                    instances.iterator();
            while (iterator.hasNext()) {
                RunningInstanceEntry instance = iterator.next();
                if (instance.worker.done()) {
                    iterator.remove();
                }
            }
        }
    }
}

注意:此代码中还有很多其他改进机会,我个人认为认为它有一个良好编码实践的例子。尽管如此,我仍然倾向于不要偏离原始代码,因为我的目标是强调使用仅结构类和iterator.remove()方法。

答案 1 :(得分:0)

感谢您的建议!

以下是我将要实施的简写版本:

public class frontpage implements Runnable {

    private class Monitor implements Runnable {
        private String x;
        public Monitor(String x) {
        this.x = x;
        }

        @Override
        public void run() {
            System.out.println("monitor task " + x);

            ConcurrentHashMap<String, Batch> batchlist = new ConcurrentHashMap<>();
            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
            ScheduledFuture<?> countdown = null;

            for (int i = 0; i < 10; i++) {
                batchlist.put("monitor " + i, new Batch(
                        "monitor task " + Integer.toString(i)));
            }

            for (String key : batchlist.keySet()) {
                countdown = scheduler.schedule(batchlist.get(key), 5, TimeUnit.SECONDS);
            }

            while (!countdown.isDone()) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            scheduler.shutdown();
            System.out.println("monitor " + x + "completed");
        }        
    }

    private class Batch implements Runnable {

        private String x;

        public Batch(String x) {
            this.x = x;
        }
        @Override
        public void run() {

            ConcurrentHashMap<String, Task> tasklist = new ConcurrentHashMap<>();
            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
            ScheduledFuture<?> countdown = null;

            for (int i = 0; i < 10; i++) {
                tasklist.put("task " + i, new Task(
                        "batch task " + Integer.toString(i)));
            }

            for (String key : tasklist.keySet()) {
                countdown = scheduler.schedule(tasklist.get(key), 5, TimeUnit.SECONDS);
            }

            while (!countdown.isDone()) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            scheduler.shutdown();
        }        
    }

    private class Task implements Runnable {

        private String x;

        public Task(String x) {
            this.x = x;
        }

        @Override
        public void run() {
            System.out.println(x + " task completed");
        }
    }

    public static void main(String args[]) {
        frontpage thisone = new frontpage();
        thisone.run();
    }

    @Override
    public void run() {
        //run once
        Task once = new Task("once");
        once.run();
        //batch
        Batch batch = new Batch("batch");
        batch.run();
        //monitor
        Monitor monitor = new Monitor("monitor");
        monitor.run();
    }
}