James Raitsev
James Raitsev

Reputation: 96391

On threads and object creation

Lets say you have a class MyClass that has a constructor

public Myclass(SomeObject o)

Myclass, additionally has a method public void doSomethingCleverWith(String s)

I'd like for MyClass to be executed as a Thread, so I

Thread t = new Thread(new MyClass(SomeObject));

When executing this thread, however run, will need to call doSomethingCleverWith(String). run, however (as i understand it) does not take in any parameters.

How would you recommend i handle this? Should String s be a part of a MyClass's constructor? Can i somehow do something else?

Upvotes: 0

Views: 101

Answers (4)

Trevor Freeman
Trevor Freeman

Reputation: 7232

This depends on the intended lifecycle of MyClass. If you have a situation where MyClass(SomeObject) is supposed to act on multiple different Strings over the course of its life, then you can avoid additional object construction by handing String instances to it through some method instead of in the constructor.

If MyClass(SomeObject) is only ever going to act on one String, then you should pass the String in during construction (or you could still pass it via another method before starting MyClass if the creation of MyClass should be separate from its use).

Assuming you want multiple Strings to be processed per MyClass instance, and the reason for the separate thread is simply for asynchronous processing, then I would use a BlockingQueue implementation to have a single thread that processes requests asynchronously (using a separate AsyncProcessor that wraps my existing synchronous processor). Eg:

public interface StringProcessor
{
  public void processString(String string);
}

public class AsyncProcessor implements StringProcessor
{
  private final ArrayBlockingQueue<String> queue;
  private final StringProcessor immediateProcessor;

  private AsyncProcessor(StringProcessor immediateProcessor, int maxQueue)
  {
    this.queue = new ArrayBlockingQueue(maxQueue);
    this.immediateProcessor = immediateProcessor;
    Thread thread = new Thread(new ProcessingTask());
    thread.start();
  }

  // Add string to queue for asynchronous processing later.
  public void processString(String string)
  {
    queue.offer(string);
    // Handle / log insert failure (queue full, maybe throw an Exception)
  }

  private class ProcessingTask implements Runnable
  {

    public volatile boolean running = true;

    public void run()
    {
      while(running)
      {
        // Probably need to deal with InterruptedException here...
        immediateProcessor.processString(queue.take());
      }
    }
  }
}

public class MyProcessor implements StringProcessor
{
  private final SomeObject someObject;

  public MyProcessor(SomeObject someObject)
  {
    this.someObject = someObject;
  }

  public void processString(String string)
  {
    // Process the string...
  }
}

public static void main(String[] args)
{
  SomeObject myObject = new SomeObject();
  StringProcessor myProcessor = new MyProcessor(SomeObject myObject);
  StringProcessor asyncProcessor = new AsyncProcessor(myProcessor,100);

  asyncProcessor.processString("This string will be processed asynchronously");
}

Upvotes: 0

Brian Roach
Brian Roach

Reputation: 76898

You could either use the Builder Pattern to ensure your MyClass objects is constructed correctly, or simple dependency injection as you suspect (passing the String to the MyClass constructor).

Upvotes: 1

Brian Agnew
Brian Agnew

Reputation: 272257

Given the above, I would make MyClass implement Runnable, and take SomeObject as a construction parameter to populate a field.

Your implementation of run() would then invoke your class using that field as a parameter.

Don't forget to call start() on the Thread btw., and not run().

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500415

You don't execute an object on a thread - you execute code on a thread... the code specified by the run() method of the runnable that you pass in to the Thread constructor, assuming you're doing it that way.

It's not really clear what you're trying to do, but it sounds like you probably need to pass the extra information (the string) to the constructor of MyClass... or execute it in a different way, such as:

final MyClass tmp = new MyClass(SomeObject));
Thread t = new Thread(new Runnable() {
    @Override public void run() {
        tmp.doSomethingCleverWithString(someValueHere);
    }
});

If you clarify what you're trying to achieve, we may be able to help you more.

Upvotes: 4

Related Questions