据我所知,以下代码应生成运行中的本地ProcessingThread
的4个克隆,并产生输出:
processing 0
processing 1
processing 2
processing 3
但是,当我尝试运行此程序时,却得到了:
java.lang.CloneNotSupportedException
public class Test {
public static void main(String[] args) {
Test o = new Test();
try {
o.process(o.new ProcessingThread() {
public void run() {
System.err.println("processing " + index);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public void process(ProcessingThread template) throws CloneNotSupportedException {
// Try run 4 parallel processing threads from the supplied template...
for (int i = 0; i < 4; i++) {
ProcessingThread thread = (ProcessingThread) template.clone();
thread.setIndex(i);
thread.start();
}
// ...
}
public class ProcessingThread extends Thread implements Cloneable {
int index;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void setIndex(int i) {
index = i;
}
}
}
请帮助我理解这一点?以及如何纠正此问题
答案 0 :(得分:11)
只需查看Thread
类的源代码:
/**
* Throws CloneNotSupportedException as a Thread can not be meaningfully
* cloned. Construct a new Thread instead.
*
* @throws CloneNotSupportedException
* always
*/
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
克隆线程根本没有意义。
答案 1 :(得分:5)
Thread
是不可克隆的。因此,呼叫super.clone()
最终会抛出CloneNotSupportedException
。
无法克隆线程,因为,那真是个坏主意。如果线程已经在运行,并且已经获取了一个条件变量,那该怎么办...原始线程和克隆都应该在同一个变量上加锁吗?
似乎您要尝试的是创建一个工作线程子程序的多个实例。如果基础子程序没有按实例的任何可变状态,执行此操作的一种简单方法是改为传递Runnable
,然后从中创建(多个)线程。实际上,尽管如此,根据您的确切用例,您可能会从ExecutorService
之类的东西中获得更多收益,这可能与您尝试(重新)实现的目标非常相似。
答案 2 :(得分:1)
根据文档,Thread类在调用clone时总是抛出该异常。由于您只是调用Thread的clone方法而不是实现自己的方法,因此它总是会引发该异常。
请参阅: https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#clone()
答案 3 :(得分:1)
您不想使用clone()而是要使用Function或lambda来创建任务。
public class Test {
public static void main(String[] args) {
Test o = new Test();
o.process(ProcessingThread::new);
}
public void process(TaskBuilder template) {
// Try run 4 parallel processing threads from the supplied template...
for (int i = 0; i < 4; i++) {
new Thread(template.build(this, i)).start();
}
// ...
}
interface TaskBuilder {
Runnable build(Test t, int index);
}
static class ProcessingThread implements Runnable {
final int index;
private final Test test;
public ProcessingThread(Test test, int index) {
this.test = test;
this.index = index;
}
@Override
public void run() {
System.out.println(test + " processing " + index);
}
}
}
但是,使用模板将N个任务进行不同处理的一种更简单的方法是使用并行流。
public static void main(String[] args) {
IntStream.range(0, 4).parallel()
.forEach(index -> System.out.println("processing " + index));
}
打印
processing 2
processing 3
processing 0
processing 1
因为不能保证任务的处理顺序。