Java多线程,Thread.sleep会暂停当前线程,但不会继续其他线程

时间:2019-12-12 18:40:06

标签: java multithreading

我正在使用Java的对象池设计模式来实践自己。并创建示例并尝试运行我的代码。

程序在池中提供有限数量的对象,并在异步进程中提供运行数量。

我的代码只需从池中拾取一个对象(如果没有可用对象并且对象数小于限制,则创建新对象),然后在Thread.sleep之后返回。但是以某种方式,其他线程继续循环运行,找不到任何可用的对象。

public abstract class ObjectPool<T> {

    private long waitingTime;
    private int maxObjectPoolSize;

    private final List<T> available = Collections.synchronizedList(new ArrayList<>());
    private final List<T> inUse = Collections.synchronizedList(new ArrayList<>());

    protected AtomicInteger count = new AtomicInteger(0);
    private AtomicBoolean waiting = new AtomicBoolean(false);

    public abstract T create();

    public ObjectPool(int poolSize) {
        waitingTime = 1200;
        setMaxObjectPoolSize(poolSize);
    }

    public void setMaxObjectPoolSize(int poolSize) {
        this.maxObjectPoolSize = poolSize;
    }

    public synchronized T getObject() {
        if (!available.isEmpty()) {
            T o = available.remove(0);
            inUse.add(o);
            return o;
        }
        // if max pool size, wait for object to be released
        if(count.get() == maxObjectPoolSize) {
            this.waitUntilNextAvailable();
            return this.getObject();
        }
        // if no objects available, create new one
        T o = this.create();
        this.inUse.add(o);
        return o;
    }

    public synchronized void releaseObject(T o) {
        this.inUse.remove(o);
        this.available.add(o);
        System.out.println(o.toString() + " is free");
    }

    private void waitUntilNextAvailable() {
//        if (waiting.get()) {
//            waiting.set(false);
//            throw new ObjectNotFoundException("No Object Available");
//        }
//        waiting.set(true);
        System.out.println(Thread.currentThread().getName());
        waiting(waitingTime);
    }

    public void waiting(long ms) {
        try {
            TimeUnit.MILLISECONDS.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }
}
public class ProcessThread implements Runnable {

    private RoomPool pool;

    public ProcessThread(RoomPool pool) {
        this.pool = pool;
    }

    @Override
    public void run() {
        takeAnObject();
    }

    private void takeAnObject() {
        try {
            System.out.println("New process: " + Thread.currentThread().getName());
            Room room = pool.getObject();

            TimeUnit.MILLISECONDS.sleep(randInt(1000, 1500));

            pool.releaseObject(room);
            System.out.println("executed: " + Thread.currentThread().getName());
        } catch (InterruptedException | ObjectNotFoundException e) {
            System.out.println(">>>> Process Rejected: " + Thread.currentThread().getName());
        }
    }

    private static int randInt(int min, int max) {
        return new Random().nextInt((max - min) + 1) + min;
    }
}
public class Main {

    public static final int OBJECT_POOL_SIZE = 4;

    public static final int NUMBER_OF_PROCESSES = 10;

    public static void main(String[] args) {
        RoomPool pool = new RoomPool(OBJECT_POOL_SIZE);
        for (int i = 1; i <= NUMBER_OF_PROCESSES; i++) {
            Runnable process = new ProcessThread(pool);
            Thread thread = new Thread(process);
            thread.start();
        }
    }
}

New process: Thread-5
New process: Thread-8
New process: Thread-3
New process: Thread-0
New process: Thread-4
New process: Thread-6
New process: Thread-7
New process: Thread-2
New process: Thread-1
New process: Thread-9
Room name = Room 1 is created
Room name = Room 2 is created
Room name = Room 3 is created
Room name = Room 4 is created
Thread-7
Thread-7
Thread-7
Thread-7
Thread-7
Thread-7

我不知道为什么线程不会返回池中的对象。

我试图在我的IDE上调试它,然后看到线程处于SLEEP状态,然后进入MONITOR。我是这种多线程技术的新手,所以我不知道这是否正常。

任何帮助将不胜感激

3 个答案:

答案 0 :(得分:2)

您已使ObjectPool的方法同步。

这意味着没有线程可以“释放”对象({synchronized releaseObject(T o),如果有任何线程已经“获取”对象synchronized getObject()

与其让整个方法同步,不如找到一种方法来仅修改inUse / available atomic。

尝试从“ getObject”中删除已同步的对象,而是仅同步列表中的第一次添加/删除,例如:

public T getObject() {
    if (!available.isEmpty()) {
        synchronized(this) {
            T o = available.remove(0);
            inUse.add(o);
        }
        return o;
    }
    ....

答案 1 :(得分:2)

一个线程正在连续递归中调用getObject()。因为此线程将锁锁定在池上(getObject()已同步),所以任何线程都无法将对象返回到池中(因为releaseObject()已同步)。

在实现池时,请使用不会阻止资源释放的并发数据结构。发布应该始终是非阻塞的。

答案 2 :(得分:1)

这里出现了对象锁定的情况。线程(abc)将调用 synchronized getobject()达n次。它将保持锁定状态,以便在此之前,没有线程能够访问同步 getRelease()方法。查看以下创建对象池的方法。

OR

您可以使用Java阻塞队列来创建对象池。阻塞队列也是线程安全的。

OR

请参考下面的链接来创建对象池 https://dzone.com/articles/generic-and-concurrent-object