我正在编写一个涉及Process
es的多线程工作池的Java程序。类Process
的每个实例都需要能够生成一个额外的线程来完成一些工作。但是线程应该由实例本身和其他人产生。不幸的是Runnable.run
是'公开的'所以如果不做一些技巧我就无法真正强制执行。
这是我打算使用的技巧:
Runnable
Process
代码:
class Process implements Runnable {
private boolean threadkey = false;
public void run() {
synchronized(threadkey) {
// is someone wrongly calling 'run'?
if(!threadkey)
return;
/* switch off threadkey to make sure
it cannot be called meaningfully again */
threadkey = false;
}
/* continue processing
*
*/
return;
}
当然,现在我需要做的就是run
合法地在打电话之前打开'threadkey'(私有)。
优雅?或不?或者,还有更好的方法?或者我是否应该在执行此操作时不费心并编写一个简洁的小评论来解释不要调用'run'?
人们甚至会在需要进行'跑步'的班级内打电话'跑'吗?
答案 0 :(得分:10)
如果你认为run
的{{1}}方法是公开的,那么你可以做的一件事就是阻止其他人调用它,那就是让整个Runnable
实现一个包-private类或私有内部类。这样,虽然它可能有Runnable
public
方法,但自定义类以外的代码无法实例化run
对象。如果您的班级也没有回复对它的引用,那么客户端将无法访问Runnable
,因此他们无法调用Runnable
。也就是说,没有run
类工具Process
;相反,创建另一个实际实现Runnable
的类,然后使Runnable
成为唯一可以访问它的类。
这种方法比你提出的方法更优雅,因为它阻止其他代码在编译时而不是在运行时调用Process
。特别是,如果任何代码试图调用上面描述的run
方法,它将编译得很好,并且会在运行时失败。问题是代码将编译但永远不会正常工作。使run
无法访问意味着如果有人试图运行它,他们将得到编译时错误,并且必须重新考虑他们的设计。换句话说,编译器会在错误发生之前检测到它。
一般情况下,如果您发现自己想要阻止随机代码调用必须公开的类的方法,因为它们是在接口中声明的,请考虑更改整个类的访问说明符,以便客户端可以'引用它。
答案 1 :(得分:6)
您可以使用Runnable
这样的匿名内部类:
private void spawnThread() {
Thread t = new Thread( new Runnable(){
public void run(){
// do something
}
}
t.start();
}
并且spawnThread()
只能从类中调用,因为它是私有的。
答案 2 :(得分:1)
您可以将run()方法设为private,并使用内部类(实现Runnable)来访问它:
public class Process {
private Thread extraThread = null;
private void run() {
// Do you thing
}
public synchronized void spawnExtraThread() {
if(extraThread != null)
return; // Do nothing an extra thread was already spwaned
extraThread = new Thread() {
public void run() { Process.this.run(); }
};
extraThread.start();
}
}
重点是类Process()不再实现Runnable,因此不能再转换为Thread。当然,您扩展此设计以支持线程数量的任何限制(只需将extraThread字段更改为线程数组)。
答案 3 :(得分:0)
只想加上我的两分钱,这是一个优雅的解决方案,它使用了Executors
和尚未提及的double colon operator (::):
import java.util.concurrent.Executors;
public class PrintFoo {
public void run() {
Executors.newSingleThreadExecutor().execute(this::doRun);
}
private void doRun() {
for (int i = 20; i --> 0;) System.out.println("Foo");
}
}
然后是调用它的类:
public class Main {
public static void main(String[] args) throws InterruptedException {
new PrintFoo().run();
System.out.println("Going to sleep...");
Thread.sleep(10000L);
}
}
输出:
Going to sleep...
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo
Foo