首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java多线程,Thread.sleep暂停当前线程,但不会继续其他线程

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

Stack Overflow用户
提问于 2019-12-12 18:40:06
回答 3查看 175关注 0票数 1

我正在使用对象池设计模式()来练习我自己。并创建了示例并试图运行我的代码。

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

我的代码只需从池中选择一个对象(如果没有可用的对象,并且对象的数量低于限制,则创建新对象),然后在Thread.sleep之后返回。但是其他线程一直在循环,无法找到任何可用的对象。

代码语言:javascript
复制
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();
        }
    }
}
代码语言:javascript
复制
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;
    }
}
代码语言:javascript
复制
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();
        }
    }
}
代码语言:javascript
复制
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上调试它,然后我看到线程处于休眠状态之后,它就会进入监视状态。我对多线程很陌生,所以我不知道这是否正常。

如能提供任何帮助,将不胜感激。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-12-12 18:52:36

您已经使ObjectPool的方法同步了。

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

与其使整个方法同步,不如找到一种只对inUse/available原子进行修改的方法。

尝试从"getObject“中删除同步,而只同步列表中的第一个添加/删除,如下所示:

代码语言:javascript
复制
public T getObject() {
    if (!available.isEmpty()) {
        synchronized(this) {
            T o = available.remove(0);
            inUse.add(o);
        }
        return o;
    }
    ....
票数 2
EN

Stack Overflow用户

发布于 2019-12-12 18:54:11

一个线程在连续递归中调用getObject()。因为这个线程持有池上的锁(getObject()是同步的),所以任何线程都不能将对象返回到池(因为releaseObject()是同步的)。

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

票数 2
EN

Stack Overflow用户

发布于 2019-12-12 19:45:47

在这里,ojbect锁定的情况出现在图片中。当线程(Abc)将调用同步 getobject() n次时。它将保持锁,以便在此之前没有线程能够访问同步 getRelease()方法。签出以下创建对象池的方法。

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59310914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档