这是一个很好的方法来进行Java类的多个函数的线程化和同步吗?

时间:2015-02-19 01:09:12

标签: java multithreading synchronization

我有一个类Prefs,它有各种方法。我需要使用线程和同步重写它。

我正在看这个变体:http://tutorials.jenkov.com/java-concurrency/synchronized.html

目前:

class T_readConfigFile extends Thread {
  protected Prefs p = null;
  public T_readConfigFile(Prefs p) {
    this.p =p;
  }

  public void run() {
    p.readConfigFile();
  }
} 

 public synchronized void readConfigFile() { ...

但不知何故为我想要线程化的每个方法制作N个相同的类并不是一个好主意。我假设它是this.p = p中的整个类;被加载到内存中 - 如果我只使用一种方法,我真的需要吗?

所以:这有效,但我不喜欢它,有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

假设您想在后台线程中调用某个方法foo()。您已经发现了最基本的方法。对于你所做的事情,这里有一个更好的变化:

new Thread(new Runnable() {
    @Override
    public void run() {
        foo();
    }
}).start();

好的,所以我写了六行Java代码来调用一个函数。是的,那种冗长。欢迎使用Java(或至少欢迎使用Java7。如果可以在Java8中更简洁地完成,我还没有学会如何。)

这种方法有一些比冗长更糟糕的问题:

1)每次要调用背景方法时,都会创建并销毁新线程。创建和销毁线程相对昂贵。

2)如果后台任务相对于调用它们的频率需要花费大量时间,则无法控制同时运行它们的数量。在繁忙的应用程序中,它可能会持续增长,直到您收到OutOfMemoryError。

更好的方法是使用线程池:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
...
final int NUM_THREADS = ...;
final ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
...
executorService.submit(new Runnable() {
    @Override
    public void run() {
        foo();
    }
});

每次向线程池提交新任务时,它都会唤醒已经存在的线程,线程将执行该任务,然后返回休眠状态。除非池启动,否则不会创建或销毁任何线程。

此外,如果在提交新任务时所有线程都忙,则该任务将被添加到队列中,稍后当工作线程可用时将执行该任务。

这只是一个简单的例子:java.util.concurrent包为您提供了更多选项,包括限制队列大小的能力,根据demans使线程池增长或缩小的能力,以及可能大多数重要的是,等待任务完成的能力,以及从已完成的任务中获取返回值的方法。

检查出来。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-frame.html

答案 1 :(得分:0)

synchronized方法锁定方法的类对象,以便一次只能有一个线程执行该方法。例如,这对于您不希望多个线程同时读取或写入同一文件或流的情况非常有用。

如果您需要每个线程读取其自己的单独配置文件,您可能不需要同步readConfigFile()方法。另一方面,如果每个线程都读取相同的配置文件, do 需要同步它。

但是如果所有线程都在读取相同的配置文件,那么你应该只有一个线程(或者可能是主父线程)读取文件一次,然后然后将生成的解析配置值传递给每个线程。这节省了大量的I / O.