0

I'm creating a twitter bot at the moment.

I have a listener listening for a status that contains a certain hashtag - #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. So, I'm thinking a suitable alternative would be to use an ArrayList<Thread> threads as such:

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.

screeb
  • 625
  • 6
  • 20
  • If a new Thread is created, you will lose the reference to it, but the thread will continue. Do you need to keep the reference to it? Anyway, to answer your question, look at ThreadGroups. – Steve Smith Apr 26 '17 at 14:28
  • @SteveSmith I think I'll need to be able to hold onto the reference, as I want to be able to stop the thread if the user tweets that they want to stop playing. – screeb Apr 26 '17 at 14:32
  • You will create a new thread each time you call `onTweet`. The variable `t` will not be "overwritten" because it goes out of scope as soon as the method ends. An list of threads is one solution, but how will you know which thread to kill? You might need something like a `Map`. You will want to consider the situation where they tweet `#DealMeIn` twice as well – Michael Apr 26 '17 at 14:33
  • @Michael Yeah a hashmap sounds like it'd be a better alternative so as to keep track accordingly. I think Twitter doesn't allow you to tweet the same thing twice in a short space of time, but I suppose it can't hurt to be sure here. Thanks. – screeb Apr 26 '17 at 14:37

2 Answers2

2

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.

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.

If you are not aware of Java's executor service then below are few quick points to get you started:

  • Java's utility class Executors will create and return objects of ExecutorService (please note that ExecutorService is an interface).
  • Now in case of newCachedThreadPool(), newFixedThreadPool(int nThreads) you will get an object of ThreadPoolExecutor (please note that ThreadPoolExecutor implements ExecutorService interface).
  • When you do 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.
  • Now, with 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.
  • 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. So, depending on your system capacity / application load you can start with corePoolSize of let say 100 and set maximumPoolSize as 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

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.

public void onTweet() {
  executorService.execute(new Game());
}
hagrawal7777
  • 14,103
  • 5
  • 40
  • 70
  • Is it possible to stop a particular thread with ExecutorService? I know you can use shutdown() and shutdownNow() in order to shutdown all threads, or force them to shut down in the latter, but is it possible to shut down a particular user's thread when they want to stop playing by tweeting the exiting hashtag "#DealMeOut"? – screeb Apr 26 '17 at 17:50
  • Yes. For that you can use same approach as what you would do in your solution or @Michael's solution, I am just outlining a far better and elegant approach to do it in standard and Java provided API way. To answer your question specifically - in order to play game I believe you would running the thread in a loop, so in order to free/stop the thread you need to end the loop, that's it, if the `run` method of your `Runnable` is completed then that thread is free and will go in thread pool to be used later. If you want to read more you can google on how to stop a thread. – hagrawal7777 Apr 26 '17 at 17:58
  • To get started read this - http://stackoverflow.com/questions/10961714/how-to-properly-stop-the-thread-in-java Do not hesitate to let me know if you have any question. – hagrawal7777 Apr 26 '17 at 17:58
0

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.

Michael
  • 41,989
  • 11
  • 82
  • 128