简体   繁体   English

如何在多线程应用程序中存储线程

[英]How to store threads in a multi-threaded application

I'm creating a twitter bot at the moment. 我现在正在创建一个Twitter机器人。

I have a listener listening for a status that contains a certain hashtag - #DealMeIn. 我有一个侦听器,在侦听包含某个#标签的状态-#DealMeIn。 When a status is found with this hashtag, I have a method that creates a new thread, that plays a game: 当使用此主题标签找到状态时,我有一个方法可以创建一个新线程,并玩一个游戏:

public void onTweet() {
  Thread t = new Thread(new Game());
  t.start();
}

The problem with the above method, if I'm not mistaken, is that t will be overwritten each time a tweet is found. 如果我没记错的话,上述方法的问题是,每次找到推文时,t将被覆盖。 So, I'm thinking a suitable alternative would be to use an ArrayList<Thread> threads as such: 因此,我在考虑一种合适的替代方法是像这样使用ArrayList<Thread> threads

public void onTweet() {
  threads.add(new Thread(new Game()));
  threads.get(threads.size()-1).start();
}

Is this a suitable way to handle my threads? 这是处理我的线程的合适方法吗?

Edit: If a user tweets, for instance, #DealMeOut then I need to be able to stop the thread. 编辑:如果用户鸣叫,例如#DealMeOut,那么我需要能够停止线程。

Answer given by @Michael is fine but I would prefer to get this job done by using Java's executor service , because it gives more control, elegant way to do this and that's what Java provided API to deal with these kind of situations. @Michael给出的答案很好,但是我更愿意通过使用Java的执行服务来完成这项工作,因为它提供了更多的控制,优雅的方式来执行此操作,而这正是Java提供的API来处理此类情况。

See below code example. 请参见下面的代码示例。 Clear advantage of this approach is that you can control maximum number of threads running in your JVM, which is extremely important otherwise over period of time your application may start clocking, so this is gives more scalability to your application/solution . 这种方法的明显优势是,您可以控制JVM中运行的最大线程数, 这非常重要,否则在一段时间内您的应用程序可能会开始计时,因此这为您的应用程序/解决方案提供了更大的可伸缩性

If you are not aware of Java's executor service then below are few quick points to get you started: 如果您不了解Java的执行程序服务,那么以下是一些快速入门指南:

  • Java's utility class Executors will create and return objects of ExecutorService (please note that ExecutorService is an interface). Java的实用程序类Executors将创建并返回ExecutorService对象(请注意, ExecutorService是一个接口)。
  • Now in case of newCachedThreadPool() , newFixedThreadPool(int nThreads) you will get an object of ThreadPoolExecutor (please note that ThreadPoolExecutor implements ExecutorService interface). 现在,在newCachedThreadPool()newFixedThreadPool(int nThreads)情况下,您将获得ThreadPoolExecutor的对象(请注意, ThreadPoolExecutor实现了ExecutorService接口)。
  • When you do Executors.newFixedThreadPool(2); 当您执行Executors.newFixedThreadPool(2); , you only get an object of ThreadPoolExecutor with all instance variables like core pool size, max pool size etc. set, and in your case it will be set to 2. ,您只会得到一个ThreadPoolExecutor对象,该对象具有所有实例变量,例如核心池大小,最大池大小等。并且在您的情况下,它将被设置为2。
  • Now, with private final static ExecutorService executorService = Executors.newFixedThreadPool(2); 现在,使用private final static ExecutorService executorService = Executors.newFixedThreadPool(2); you will always have max of 2 threads in your JVM for this thread pool, and any excess request will get queued up in LinkedBlockingQueue implementation, and since LinkedBlockingQueue is a unbounded queue so you will never loose your task. 对于该线程池,您的JVM中将始终最多有2个线程,并且任何多余的请求都将在LinkedBlockingQueue实现中排队,并且由于LinkedBlockingQueue是一个无界队列,因此您永远不会丢失任务。
  • Suppose you want to create more threads when you have more load then you have to play around with maximumPoolSize and use a bounded queue. 假设您想在负载更多时创建更多线程,则必须使用maximumPoolSize并使用有界队列。 So, depending on your system capacity / application load you can start with corePoolSize of let say 100 and set maximumPoolSize as Integer.MAX_VALUE . 因此,根据您的系统容量/应用程序负载,您可以从让corePoolSize设为100开始,然后将maximumPoolSize设置为Integer.MAX_VALUE

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceImplementationExample {
    private final static int MAX_NUMBER_OF_THREADS = Integer.MAX_VALUE;

    // set maximum number of threads as per your requirement/performance tuning, for testing set it to "2" and to have better feel.
    private final static ExecutorService executorService = Executors.newFixedThreadPool(MAX_NUMBER_OF_THREADS);


    public static void main(String[] args) {
        System.out.println("### Starting.");

        new Thread(){
            @Override
            public void run() {
                scheduleTask(new MyRunnableTask());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                scheduleTask(new MyRunnableTask());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                scheduleTask(new MyRunnableTask());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                scheduleTask(new MyRunnableTask());
            }
        }.start();

        System.out.println("### Completed.");
    }

    private static void scheduleTask(Runnable runnable) {
        executorService.execute(runnable);
    }

}

MyRunnableTask.java MyRunnableTask.java

public class MyRunnableTask implements Runnable {

    @Override
    public void run() {
        System.out.println("I am getting executed: " + this.hashCode() + " | " + Thread.currentThread().getId());
        try {
            Thread.sleep(2000); // this sleep is only for testing to give a feel of how solution will work, remove after testing.
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

In your case you will do something like below, and you need to have executorService created in the start and your Game class should implement Runnable interface. 对于您而言,您将执行以下操作,并且需要在开始时创建executorService ,并且您的Game类应实现Runnable接口。

public void onTweet() {
  executorService.execute(new Game());
}

I would create a map of users to the thread which their game is taking place on. 我会创建一个用户映射到正在运行其游戏的线程。

private Map<String, Thread> games = new HashMap<>();

public void onTweet(String user) {
    if (!games.containsKey(user)) // if they haven't got a game running
    {
        Thread t = new Thread(new Game());
        t.start();
        games.put(user, t);
    }
}

public void onStop(String user) {
    if (games.containsKey(user))
    {
        games.remove(user).interrupt();
    }
    else
    {
        //should we handle this?
    }
}

You will need to ensure the thread is prepared to deal with interrupts. 您将需要确保线程准备好处理中断。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM