信号量 - 为什么我的线程一个接一个地运行而不是并发运行?

时间:2016-09-21 07:21:30

标签: java multithreading concurrency semaphore

我正在尝试编写一个程序,在Main类中可以启动未知数量的新线程。 每个线程依次调用 Singleton Copier类,该类应该调用文件传输操作。

我的目标是,无论线程请求数量多少,都要限制并发传输到2次传输的次数,所以我想用Semaphore来解决它。 我的问题是,似乎线程一个接一个地运行而不是并发运行。

这是我尝试做的事情:

public class Copier {

    private static final int POOL_SIZE = 2;
    private static volatile Copier instance = null;
    private static Semaphore semaphore;

    private Copier() {

    }

    public static Copier getInstance() {
        if (instance == null) {
            synchronized (Copier.class) {
                if (instance == null) {
                    instance = new Copier();
                    semaphore = new Semaphore(POOL_SIZE);
                }
            }
        }
        return instance;
    }

    public void fileTransfer(CopyThread copyThread) {
        try {
            semaphore.acquire();
            System.out.println("Running thread...");
            copyThread.run();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            semaphore.release();
            System.out.println("Thread released..");
        }
    }
}

这是我的Main课程:

public class Driver {
    public static void main(String[] args) {
        Copier copier = Copier.getInstance();
        CopyThread copyThread1 = new CopyThread();
        CopyThread copyThread2 = new CopyThread();

        copier.fileTransfer(copyThread1);
        copier.fileTransfer(copyThread2);
    }
}

运行它时 - 您可以通过输出看到一个接一个地运行的线程,而我的目的是最多有两个并发线程。 我做错了什么?

Running thread...
3.998784MB were transferred in 5.902514932 seconds
Thread released..
Running thread...
4.062673MB were transferred in 7.199550077 seconds
Thread released..

2 个答案:

答案 0 :(得分:2)

您应该拨打start()而不是run(),否则它将无法启动您的线程,以便顺序完成转移,这实际上是您当前问题的根本原因。< / p>

无论如何,对我来说,你的代码应该被重写,因为类Copier甚至不应该开始()线程,因为它不是它的职责。

1。重写方法fileTransfer()

public void fileTransfer() {
    try {
        semaphore.acquire();
        System.out.println("Running transfer...");
        // Code that performs the transfer
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        semaphore.release();
        System.out.println("Thread released..");
    }
}

2。正确实施run()方法CopyThread

@Override
public void run() {
    // Here I call fileTransfer() on Copier instead of the other way around
    Copier.getInstance().fileTransfer();
}

3。使semaphore非静态和最终

private final Semaphore semaphore;

private Copier() {
    this.semaphore = new Semaphore(POOL_SIZE);
}

4。使用内部类来延迟创建实例

public class Copier {
    ...
    public static Copier getInstance() {
        return Holder.instance;
    }
    ...
    private static class Holder {
        private static final Copier instance = new Copier();
    }
}

5。重写您的main方法

public static void main(String[] args) throws Exception {
    CopyThread copyThread1 = new CopyThread();
    CopyThread copyThread2 = new CopyThread();

    copyThread1.start();
    copyThread2.start();
}

<强>输出:

Running transfer...
Running transfer...
Thread released..
Thread released..

答案 1 :(得分:1)

如果你打电话给Thread.run()你没有启动线程,你只需按顺序执行该方法。您需要致电start()。 (我假设CopyThreadThread)。

Joshua Bloch的Java Puzzlers有一章有一个非常相似的例子。