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

Semaphore - why my threads are running one after the other and not in concurrent?

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

我的目标是,无论线程请求的数量如何,限制 并发传输数为 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 class:

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);
    }
}

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

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

如果你调用Thread.run()你不启动线程,你只是按顺序执行方法。您需要致电 start()。 (我假设 CopyThreadThread)。

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

你应该调用 start() 而不是 run() 否则它不会启动你的线程,这样传输将按顺序完成,这实际上是你当前问题的根本原因。

无论如何,对我来说你的代码应该被重写为 class Copier 甚至 start() 线程都不应该,因为这不是它的职责.

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。正确实现CopyThread的方法run()

@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。使用内部 class 来延迟创建您的实例

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..