对于 Java class 的多个函数,这是线程化和同步的好方法吗?
Is this a good approach for threading and synchronization of multiple functions of a Java class?
我有一个class 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 个相同的 class 对于我想要线程化的每个方法看起来不是一个好主意。我假设它是 this.p = p 中的整个 class;被加载到内存中——如果我只使用其中的一种方法,我真的需要它吗?
所以:这个可行,但我不喜欢它,有更好的方法吗?
假设您想在后台线程中调用一些方法 foo()。你已经发现了最基本的方法。这是您所做操作的一个更可取的变体:
new Thread(new Runnable() {
@Override
public void run() {
foo();
}
}).start();
OK,所以我写了六行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 包为您提供了更多选项,包括限制队列大小的能力,使线程池根据需求增长或收缩的能力,以及也许最重要的是,等待任务完成的能力,以及从完成的任务中获取 return 值的方法。
检查一下。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-frame.html
一个synchronized
方法锁定了该方法的class 对象,这样一次只有一个线程可以执行该方法。这对于您不希望多个线程同时读取或写入同一文件或流的情况非常有用,例如。
如果你需要每个线程读取自己单独的配置文件,你可能不需要同步readConfigFile()
方法。另一方面,如果每个线程读取相同配置文件,您确实需要同步它。
但是如果所有线程都在读取同一个配置文件,也许你应该只让一个线程(或者可能是主父线程)读取文件一次,并且然后 将解析后的配置值传递给每个线程。这样可以节省很多 I/O.
我有一个class 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 个相同的 class 对于我想要线程化的每个方法看起来不是一个好主意。我假设它是 this.p = p 中的整个 class;被加载到内存中——如果我只使用其中的一种方法,我真的需要它吗?
所以:这个可行,但我不喜欢它,有更好的方法吗?
假设您想在后台线程中调用一些方法 foo()。你已经发现了最基本的方法。这是您所做操作的一个更可取的变体:
new Thread(new Runnable() {
@Override
public void run() {
foo();
}
}).start();
OK,所以我写了六行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 包为您提供了更多选项,包括限制队列大小的能力,使线程池根据需求增长或收缩的能力,以及也许最重要的是,等待任务完成的能力,以及从完成的任务中获取 return 值的方法。
检查一下。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-frame.html
一个synchronized
方法锁定了该方法的class 对象,这样一次只有一个线程可以执行该方法。这对于您不希望多个线程同时读取或写入同一文件或流的情况非常有用,例如。
如果你需要每个线程读取自己单独的配置文件,你可能不需要同步readConfigFile()
方法。另一方面,如果每个线程读取相同配置文件,您确实需要同步它。
但是如果所有线程都在读取同一个配置文件,也许你应该只让一个线程(或者可能是主父线程)读取文件一次,并且然后 将解析后的配置值传递给每个线程。这样可以节省很多 I/O.