【问题标题】:How can i run the task only once in this task我怎样才能在这个任务中只运行一次任务
【发布时间】:2013-07-17 09:27:56
【问题描述】:

我的 WebApplication 中有下面这段代码,每当用户登录应用程序时,它基本上都会这样做。

  1. addSymbols 方法将在用户登录操作期间被调用。
  2. 由于上述原因,PriorityBlockingQueue 被启动
  3. PriorityBlockingQueue 将符号添加到 HashSet 中,然后对其进行迭代以在该新添加的符号上运行特定任务。

我在这里面临的问题是,作为 HashSet 一部分的 while 循环一遍又一遍地执行相同的任务,因为它处于线程的 while true 条件内。

我正在粘贴示例输出以了解与之相关的上下文。

Symbol From priorityBlocking  SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest
Symbol From allSymbolsSet   SymbolTest

这是我完成上述操作的代码。

package com;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;

public class TaskerThread extends Thread {
    private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
    private Set<String> allSymbolsSet = new HashSet<String>();
     ExecutorService es = Executors.newFixedThreadPool(2);

    public void addSymbols(String str) {
        if (str != null) {
            priorityBlocking.add(str);
        }
    }

    public void run() {
        while (true) {
            try {
                while (priorityBlocking.peek() != null) {
                    String symbol = priorityBlocking.poll();
                    allSymbolsSet.add(symbol);
                    try {
                        System.out.println("Symbol From priorityBlocking" +"  "+ symbol);
                    }   catch (Exception e) {
                            e.printStackTrace();
                    }
                }
                Iterator<String> ite = allSymbolsSet.iterator();
                while (ite.hasNext()) {
                    String symbol = ite.next();
                    if (symbol != null && symbol.trim().length() > 0) {
                        try {
                            System.out.println("Symbol From allSymbolsSet"+"   "+symbol);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String args[]) {
        try {
            TaskerThread qT = new TaskerThread();
            qT.start();
            qT.addSymbols("SymbolTest");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果有什么方法可以让迭代器任务只运行一次,请告诉我。

【问题讨论】:

  • 我不能在while true条件之外保留迭代部分代码,因为如果我这样做,如果任何新用户登录,我将错过要执行的任务。
  • 不确定它是否能解决任何问题,但您可能想使用take 或poll(long,TimeUnit),因为它们会阻止。当队列中没有任何内容时,这将阻止循环运行。然后你应该也可以删除手册sleep。
  • 您在 allSymbolsSet 中添加了符号,但您从不删除它们。因此,在您的 while(true) 内,您将始终打印所有符号
  • @fluminis 如何从 allSymbolsSet 中删除符号?因为每个用户都有一个独特的符号。

标签: java multithreading


【解决方案1】:

我明白了。以下是正在发生的事情:

您的循环开始,并且一个符号被添加到队列中。它在线程循环中被拉出队列,然后迭代器循环运行。然后外层循环 (while (true)) 再次循环,这一次,没有要添加的符号,但迭代器循环仍然执行。如果添加了新符号,您只需要执行迭代器循环:

            boolean added = false;
            while (priorityBlocking.peek() != null) {
                added = true;
                String symbol = priorityBlocking.poll();
                allSymbolsSet.add(symbol);
                try {
                    System.out.println("Symbol From priorityBlocking" +"  "+ symbol);
                }   catch (Exception e) {
                        e.printStackTrace();
                }
            }
            if (added) {
                Iterator<String> ite = allSymbolsSet.iterator();
                while (ite.hasNext()) {
                    String symbol = ite.next();
                    if (symbol != null && symbol.trim().length() > 0) {
                        try {
                            System.out.println("Symbol From allSymbolsSet"+"   "+symbol);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

或者,使用take 或poll(long,TimeUnit) 也会停止循环,而您没有任何要添加的内容。这也应该防止循环的第二部分不必要地运行。您只需要处理InterruptedException。

【讨论】:

  • 我拿走了你的代码并运行了它,但我仍然看到迭代器不断地被执行。这是预期的,因为一旦标志设置为 true,它就会持续运行知道,如果我错过了什么,请告诉我。
  • 该标志是 try 块的本地标志。每次循环进行时,它都应该获得一个新值。如果你只添加一次,那么它应该只执行一次。如果添加多个项目,则每次添加时都会执行。
  • 谢谢,有道理,现在试了一下,看起来不错,这工作正常,但你能告诉我,如果我使用取自priorityBlockingQueue而不是你粘贴的上述代码,我会得到什么好处。
  • 目前,无论是否有任何事情要做,外部white (true) 循环每2 秒运行一次。当什么都不添加时,整个迭代本质上是对 CPU 周期的浪费。通过使用take,线程将完全处于非活动状态,直到将某些内容添加到队列中。这将减少对处理器时间的争用,因此实际上有工作要做的其他线程可以这样做。不过,使用take 可能需要对代码进行更重大的修改。多线程有时会很痛苦。
猜你喜欢
  • 2016-03-12
  • 2018-07-01
  • 2015-10-05
  • 1970-01-01
  • 2011-09-21
  • 2020-10-22
  • 2022-01-09
  • 1970-01-01
  • 2013-01-12
相关资源
最近更新 更多