2

我是使用线程的新手,只是想弄清楚。我的最终游戏是拥有一个 URL 列表,我的程序将一次从列表中获取一个 URL,并使用该 URL 执行操作。会有很多 URL,当一些线程使用同一个列表时,可能会添加这个列表。

为了开始实验和学习,我使用了一个简单的 ArrayList 填充数字,并使用线程池来获取 URL。这是我的代码:

public static void main(String[] args) {

    for (int i = 0; i < 200; i++){
        test.add(i);
    }

    SlothTest runner = new SlothTest();
    Thread alpha = new Thread(runner);
    Thread beta = new Thread(runner);

    ExecutorService tasker = Executors.newFixedThreadPool(10);

    while (!listEmpty()){
        tasker.submit(new SlothTest());
    }

    tasker.shutdown();
    System.out.println("Complete...");
}

@Override
public void run() {
    getLink();
    try {
        Thread.sleep(20);
    } catch (InterruptedException e) {
    }
}

private synchronized String getLink(){
    link = Thread.currentThread().getName() + " printed " + test.indexOf(test.size()-1);
    test.remove(test.size()-1);
    System.out.println(link);
    return link;
}

private synchronized static boolean listEmpty(){
    if (test.size() > 0){
        return false;
    } else {
        return true;
    }
}

在运行程序并为我的输出获得一些-1 时,我遇到了一些并发问题。我不确定为什么会发生这种情况,我知道我上面的代码很粗糙,但我真的处于学习阶段的多线程应用程序。任何人都可以先帮我解决我的并发问题,然后如果你能给我关于我上面的代码的任何指示,那也很好

4

3 回答 3

3

一个问题是

while (!listEmpty()){
    tasker.submit(new SlothTest());
}

不是原子的。所以listEmpty可能会返回 false,但在您到达下一个语句时变为 true。

另一个是您在两个不同的监视器上同步:

private synchronized String getLink(){ //synchronized on this

private synchronized static boolean listEmpty(){//synchronized on this.class

您是否考虑过使用 aBlockingQueue而不是列表,它为您想要实现的目标提供了有用的方法。

于 2012-09-11T15:30:10.983 回答
2

尝试为您的 URL 列表使用ConcurrentLinkedQueue 。这是一个很好的实现,经常在生产者-消费者示例中使用,类似于您的(尽管您本身没有活动的“生产者”)。

于 2012-09-11T15:30:09.283 回答
2

你不是全局同步的。通过使用synchronized方法,您可以锁定当前实例,这对于每个任务都是不同的。您应该改用全局锁:

final static Object globalLock = new Object();

private String getLink() {
   synchronized (globalLock) {
      link = Thread.currentThread().getName() + " printed " + test.indexOf(test.size()-1);
      test.remove(test.size()-1);                    
   }
   System.out.println(link);
   return link;
}

private boolean listEmpty(){
    synchronized (globalLock) {
       if (test.size() > 0){
          return false;
       } else {
          return true;
       }
    }
}
于 2012-09-11T15:29:07.693 回答