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

Nim*_*rod 6 java concurrency multithreading 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..");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Running thread...
3.998784MB were transferred in 5.902514932 seconds
Thread released..
Running thread...
4.062673MB were transferred in 7.199550077 seconds
Thread released..
Run Code Online (Sandbox Code Playgroud)

Nic*_*tto 3

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

无论如何,对我来说,您的代码应该被重写,因为该类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..");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

3. 使semaphore非静态和最终的

private final Semaphore semaphore;

private Copier() {
    this.semaphore = new Semaphore(POOL_SIZE);
}
Run Code Online (Sandbox Code Playgroud)

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

public class Copier {
    ...
    public static Copier getInstance() {
        return Holder.instance;
    }
    ...
    private static class Holder {
        private static final Copier instance = new Copier();
    }
}
Run Code Online (Sandbox Code Playgroud)

5.重写你的main方法

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

    copyThread1.start();
    copyThread2.start();
}
Run Code Online (Sandbox Code Playgroud)

输出:

Running transfer...
Running transfer...
Thread released..
Thread released..
Run Code Online (Sandbox Code Playgroud)