1

我正在为 OCP 考试做一些练习。目前,我尝试在使用多个线程时打印CopyOnWriteArrayList内容。根据文档, CopyOnWriteArrayList 的迭代器将

打印创建迭代器时存在的列表中的数字

因此,当在 CopyOnWriteArrayList 上启动一个线程写入并从 CopyOnWriteArrayList读取另一个线程时,我希望(有时)打印出一些项目。在编写线程完成后遍历 CopyOnWriteArrayList 时,我希望有一个新的迭代器打印出所有项目

不幸的是,这在使用Runnable 接口的匿名实现时不起作用。但它在使用自定义线程类时有效,我在其中传递了对 CopyOnWriteArrayList 的引用。

现在,我不明白为什么会发生这种情况。我不确定是否final CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();会导致这种影响——如果是这样的话——我根本不知道为什么?

对此主题的任何意见将不胜感激!

使用 Runnable 的匿名实现 - 无法按预期工作

static void copyOnWriteCollections() {
    System.out.println("copyOnWriteCollections".toUpperCase());

    final CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();

    Thread tADD = new Thread(new Runnable() {
        public void run() {
            for (int i = 0; i < 10000; i++) {
                intList.add(i);
            }
        }
    });
    tADD.start();

    /// will print the numbers in the list which are present
    /// at the moment the iterator is created
    Thread tREAD = new Thread(new Runnable() {
        public void run() {
            for (Integer i : intList) {
                System.out.print(i);
                System.out.print(" ");
            }
        }
    });     
    tREAD.start();

    try {
        tADD.join();
        tREAD.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    // will print out all numbers - as iterator is created when all
    // modifications
    // to intList have finished
    System.out.println();
    new Thread(new Runnable() {
        public void run() {
            System.out.println("new");
            System.out.println("\tsize of intList: " + intList.size());

            Iterator<Integer> it = intList.iterator();

            while (it.hasNext()) {
                int i = it.next();
                System.out.print(i);
                System.out.print(" ");
            }

            System.out.println("end");
        }
    }).start();
}

输出(有时 - 因为有线程) 第一个读取线程打印出一些数字,第二个读取线程不会打印出任何数字!

使用自定义线程类 - 按预期工作

class CopyOnWriteThread extends Thread {

    Iterator<Integer> it = null;
    boolean read = false;
    CopyOnWriteArrayList<Integer> intList = null;

    public CopyOnWriteThread(CopyOnWriteArrayList<Integer> intList, boolean read) {
        this.intList = intList;
        this.read = read;
    }

    public void run() {
        if (read) {
            it = intList.iterator();

            System.out.println("START read (" + Thread.currentThread().getName() + ")");
            System.out.print("\t");
            while (it.hasNext()) {
                System.out.print(it.next());
                System.out.print(" ");
            }
            System.out.println();
            System.out.println("END read (" + Thread.currentThread().getName() + ")");
        } else {
            System.out.println("START write (" + Thread.currentThread().getName() + ")");
            for (int i = 0; i < 10000; i++) {
                intList.add(i);
            }
            System.out.println("END write (" + Thread.currentThread().getName() + ")");
        }
    }
}

static void copyOnWriteCollections_CustomThread() {
    CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();

    CopyOnWriteThread tWRITE = new CopyOnWriteThread(intList, false);
    CopyOnWriteThread tREAD = new CopyOnWriteThread(intList, true);
    tWRITE.start();
    tREAD.start();

    try {
        tWRITE.join();
        tREAD.join();
    } catch (InterruptedException e) {
    }

    CopyOnWriteThread tREAD2 = new CopyOnWriteThread(intList, true);
    tREAD2.start();
}

输出 - 按预期工作 第一个读取线程打印出一些数字,第二个读取线程打印出所有数字

目前我正在使用 JDK 1.7.0_25 和 Eclipse Mars Release 4.5.0 的 Win10 机器上工作

4

1 回答 1

0

正如@user2357112 发布的那样,代码没有任何问题。问题似乎与Eclipse 相关

在 Eclipse Mars / JRE 1.7.0_25 中运行问题代码时,它不会打印出 0 到 9999 之间的数字。相反,它会立即退出,就好像没有新的迭代器一样。

我从命令行编译代码并使用 and 启动java.exejavaw.exe。两者都显示正确的输出。

java命令

java -classpath "c:\Chapter14\ConcurrentCollections\bin" concurrentCollections.TestClass

结果

命令行输出 - 相关部分

javaw 命令

javaw -classpath "c:\Chapter14\ConcurrentCollections\bin" concurrentCollections.TestClass > "c:\test.txt"

结果

测试文件内容 - 前 xxx 个数字 - 包含所有数字

现在我可以说(肯定)我的代码没有问题,JVM 也没有问题!

编辑

我通过修改Run Configurations将输出重定向到一个文件。在eclipse中重新启动应用程序。Output.txt包含所有数字 - 但在我的 Eclipse 控制台窗口(分配控制台)中,数字不会出现......

运行配置 Eclipse

于 2016-03-23T11:22:12.183 回答