好的线程设计:“线程中的方法”或“方法中的线程”

时间:2012-04-07 17:04:34

标签: java multithreading algorithm

这只是关于实际线程设计的一般问题。我特意在Android上使用Java,但一般设计将是这个问题的更好关注点。

它足够简单,这是方法中线程或线程的更好方法。

实施例,

假设我们有3种方法/功能/无论如何。

public void readMail()
{
    //Logic...
}
public void postQuestion()
{
    //Logic...
}
public void answerQuestion()
{
    //Logic...
}

拥有

更好吗?

A:方法

中的线程
public void readMail()
{
    new Thread(new Runnable()
    {
        public void run()
        {
            //Logic
        }
    }).start();
}

然后像往常一样在任何OO情况下调用您的方法。说

Email.readMail();

B:线程内的方法

//note this could be inside a method or a class that extends runnable
new Thread(new Runnable()
{
    public void run()
    {
        readMail();
        postQuestion();
        answerQuestion();
    }
}).start();

5 个答案:

答案 0 :(得分:4)

第二个选项更适合重写以使用Executor等,所以我更喜欢这个版本。

答案 1 :(得分:4)

  

线程内的方法

  • [+] 如果您的方法不需要确保并发执行的属性,或者它们具有确定性的运行时行为(时间和性能),则此方法可以是并发的高级管理申请书;即并发性仍然是对象而不是方法。
  • [ - ] 由于并发性仍处于线程/对象级别,因此应用程序可能会失去响应性的概念。用户可能是“发帖问题”而另一个是“提取答案”;两者都可以同时处理。
  

带方法的线程

  • [+] 更细粒度的并发控制:每个方法都成为操作系统级别的执行单元。这就是为什么@LouisWasserman提到,也许,利用Executor框架会更有意义。
  • [ - ] 通常,线程资源丰富昂贵;因此,这意味着在高频/负载应用中使用时会遇到性能问题,并且需要多次调用一个方法。特别是,如果存在方法间数据/逻辑依赖性。在这方面,同步也成为一个问题,这就是为什么使用 Actor 模型可以提供更多帮助。

我建议您详细了解Actor models及其可用的实施方法。

答案 2 :(得分:1)

我更喜欢:


C:一个线程一个对象

public class Test {
  public static class MailReader implements Runnable {
    public void readMail() {
      //Logic...
    }
    @Override
    public void run() {
      while (!Thread.currentThread().isInterrupted()) {
        readMail();
      }
    }
  }

  public static class QuestionPoster implements Runnable {
    public void postQuestion() {
      //Logic...
    }
    @Override
    public void run() {
      while (!Thread.currentThread().isInterrupted()) {
        postQuestion();
      }
    }
  }

  public static class QuestionAnswerer implements Runnable {
    public void answerQuestion() {
      //Logic...
    }
    @Override
    public void run() {
      while (!Thread.currentThread().isInterrupted()) {
        answerQuestion();
      }
    }
  }
  public static void main(String[] args) throws FileNotFoundException {
    new Thread(new QuestionAnswerer()).start();
    new Thread(new QuestionPoster()).start();
    new Thread(new MailReader()).start();
  }
}

这可以实现全方位的可能性,而无需任何额外的努力。如果您希望回复的邮件多于发布的问题,请填写更多MailReader s。

如果你看到

for ( int i = 0; i < 10; i++ ) {
  new Thread(new MailReader()).start();
}

您知道完全目的是什么,而您知道将会有效。

答案 3 :(得分:0)

在第一个设计(A)中,每个方法实际上都是一个单独的线程,而在第二个设计(B),你只有一个线程。
它在很大程度上取决于你的应用逻辑和每种方法执行的操作:
如果你需要并行运行你的方法,那么A是正确的答案,但如果你需要在一个线程中按顺序执行所有方法,那么B将是你的选择。

答案 4 :(得分:0)

如果要构建一个供其他程序员使用的实用程序,请注意客户端程序员可能根本不关心线程,可能只想编写单线程程序。除非有充分的理由这样做,否则你不应该强迫他们将线程问题拖到一个程序中,否则它会运行良好的单线程。这是否意味着您的库不能在内部使用线程?没有!但是对于调用者,你的方法应出现单线程(除非它们返回的速度比没有线程时实现的速度快)。

你怎么能这样做?当有人调用您的某个方法时,阻止调用线程,并将任务传递给工作线程池,工作线程可以并行执行。在工作线程完成任务后,取消阻塞调用线程并让它向调用者返回一个值。

通过这种方式,您可以获得并行性的性能优势,而无需强制调用者处理线程问题。

现在,另一方面,即使您确定您的库不需要在内部使用 仍然仍然使其成为线程安全的,因为客户端程序员可能想要使用线程。

换句话说,没有理由为什么决定“线程在方法?”和“线程中的方法?”需要耦合。如果这样做有性能优势,则可以使用“thread in method”,但这不应影响调用者。 (他们应该能够调用该方法并获得所需的返回值,而不必担心您是否在内部使用线程。)

如果您的模块是线程安全的,那么调用者是否正在使用线程也不会影响它。因此,如果客户端程序员想要使用线程,他们也可以使用“线程中的方法”。在某些情况下,您可能 “线程中的方法”和“方法中的线程” - 您的模块可能在内部使用工作线程池+任务队列,并且您可能有多个调用方线程推送任务进入队列并等待结果。

现在,虽然我说的是你正在构建一个库,但实际上你可能只是为自己建立代码。但无论如何,同样的原则也适用。如果你想使用线程来提高性能,最好在接口后面封装线程的使用,并使程序的其余部分不必知道或关心模块XYZ是否正在使用线程。同时,最好让每个模块都是线程安全的,这样调用者就可以决定是否使用线程。