线程池一次只有一个活动线程,并在任务内部产生让另一个线程运行

时间:2014-05-03 10:20:19

标签: java multithreading concurrency

我需要一个一次只执行一个任务的线程池,当一个任务调用一个特殊方法时(我们称之为checkpointyield),然后:

  • 暂停当前主题
  • 尝试查找并恢复暂停时间过长的另一个帖子
  • 如果未找到,则恢复具有其任务的最高优先级的另一个线程

我的任务大部分时间都在等待来自套接字的数据,因此Thread.setPriority()不会这样做。

现在我写了一个可能包装的东西:

static final int READ_AHEAD_NUM = 5;

public String getFile(int fileId) {
    ArrayList<String> urls = new ArrayList<String>(READ_AHEAD_NUM);
    MyDownloadJob[] jobs = new MyDownloadJob[READ_AHEAD_NUM];
    for (int i = 0; i < READ_AHEAD_NUM; i++) {
        urls.add("http://.../" + (fileId++));
    }
    // reprioritize and cancel unneeded jobs
    for (MyDownloadJob job : scheduler.getJobs()) {
        int index = urls.indexOf(job.getUrl());
        if (index == -1) {
            job.cancel();
        } else {
            jobs[index] = job;
            job.setPriority(index);
        }
    }
    MyDownloadJob job;
    // create missing jobs
    for (int index = 0; index < READ_AHEAD_NUM; index++) {
        if (jobs[index] == null) {
            jobs[index] = job = scheduler.addJob(new MyDownloadJobImpl(urls.get(index)));
            job.setPriority(index);
        }
    }

    // wait 1st job
    job = jobs[0];
    job.join();
    return job.getPath();
}

static abstract class MyDownloadJob extends Job {
    public abstract String getPath();
    public abstract String getUrl();

    private void checkpoint(int workAmount) throws Exception {
        if (super.yieldAndTestCancel(workAmount))
            throw new Exception("cancelled");
    }

    @Override
    public Object call() throws Exception {
        checkpoint(0);
        FileOutputStream fos = new FileOutputStream(getPath());
        InputStream in = MyUtils.openConnection(getUrl());
        checkpoint(0);
        byte[] buffer = new byte[512];
        int len;
        while ((len = in.read(buffer)) != -1) {
            checkpoint(len);
            fos.write(buffer, 0, len);
        }
        for(;;) {
            break;
        }
        in.close();
        fos.close();
        return null;
    }
}

2 个答案:

答案 0 :(得分:0)

我建议使用尽可能多的线程的线程池。然后,在你的worker中使用所有线程共有的信号量,在via外部创建 final Semaphore threadExecution = new Semaphore(1)

在内部,您可以通过该信号量上的aquire()和release()来控制执行。

答案 1 :(得分:0)

我看到两种方法:

  1. 每个作业使用一个线程:每当一个线程想要屈服于另一个线程时,它从线程列表中选择一个,给它一个轻推,然后等待自己依次唤醒。请注意,这意味着(至少在短时间内)两个线程同时运行,并且可能只有一个线程试图唤醒自己。
  2. 仅使用一个线程:单个线程只是从列表中选择一个作业并运行该作业。当它想要暂停当前作业并获取另一个作业时,它只是存储其数据并返回到从可用作业列表中选择作业的函数。这里的问题是你需要构建你的作业处理程序,以便它可以存储它的当前状态并在以后拾取,第一种方法是“当前状态”只是线程的堆栈,这通常更容易。
  3. 请注意,选择作业的算法(通过某个优先级的等待时间)完全独立,因此应该有一种优先级队列。