无法克隆线程-为什么?

时间:2019-01-07 16:20:11

标签: java multithreading

据我所知,以下代码应生成运行中的本地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;
        }

    }
}

请帮助我理解这一点?以及如何纠正此问题

4 个答案:

答案 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

因为不能保证任务的处理顺序。