Reputation: 1423
I'm new to using threads and just trying to figure things out. My end game is to have a list of URLs, my program will take one URL from the list at a time and perform an action using that URL. There'll be a lot of URLs and this list may possibly be added to while some threads are using the same list.
To start experimenting and learning I'm using a simple ArrayList filled with numbers and am using a threaded pool to get the URLs. Here's my code:
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;
}
}
I'm running into some concurrency issues while running the program and getting some -1's for my output. I'm not sure why this is happening and I know my above code is rough but I'm really in the learning stage a multi-threaded apps. Can anyone help me first off with fixing my concurrency issue and then if you can give me any pointers about my above code that would also be great
Upvotes: 2
Views: 165
Reputation: 62459
You're not globally synchronizing. By using synchronized
methods you are locking the current instance, which is different for each task. You should use a global lock instead:
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;
}
}
}
Upvotes: 2
Reputation: 579
Try using a ConcurrentLinkedQueue for your list of URLs. This is a good implementation often used in producer-consumer examples, similar to yours (although you don't have an active 'producer', per-se).
Upvotes: 2
Reputation: 328737
One problem is that
while (!listEmpty()){
tasker.submit(new SlothTest());
}
is not atomic. So listEmpty
might return false, but become true by the time you reach the next statement.
Another one is that you synchronize on two different monitors:
private synchronized String getLink(){ //synchronized on this
private synchronized static boolean listEmpty(){//synchronized on this.class
Have you considered using a BlockingQueue
instead of a list, which has useful methods for what you are trying to achieve.
Upvotes: 3