This code sometime throwing an Exception even i have used synchronized Method removeFirst within synchronized block of run method, I am adding and removing element on a synchronizedList.
public class NameDropper extends Thread {
private NameList n1;
public NameDropper(List list) {
this.n1 = new NameList(list);
}
public static void main(String[] args) {
List l = Collections.synchronizedList(new LinkedList());
NameDropper n = new NameDropper(l);
n.n1.add("Ozymandias");
Thread[] t = new NameDropper[10];
for (int i = 1; i <= 10; i++) {
t[i - 1] = new NameDropper(l);
t[i - 1].setName("T" + Integer.toString(i - 1));
t[i - 1].start();
}
}
public void run() {
synchronized (this) {
try {
Thread.sleep(50);
String name = n1.removeFirst();
System.out.println(Thread.currentThread().getName() + ": "
+ name);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class NameList {
private List names = null;
public NameList(List list) {
this.names = list;
}
public synchronized void add(String name) {
names.add(name);
}
public synchronized String removeFirst() {
if (names.size() > 0)
return (String) names.remove(0);
else
return null;
}
}
The exception it is throwing:
T1: Ozymandias
T2: null
*Exception in thread "T3" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.entry(Unknown Source)
at java.util.LinkedList.remove(Unknown Source)
at java.util.Collections$SynchronizedList.remove(Unknown Source)
at NameList.removeFirst(NameDropper.java:57)*
T0: null
T8: null
*at NameDropper.run(NameDropper.java:33)*
T6: null
T4: null
T9: null
T7: null
T5: null
You're creating a new NameDropper instance for each thread.
Therefore, the synchronized methods aren't actually locking, since each instance is never used by two threads.
As pointed out by other people, you have a race condition because all of your threads are synchronized on themselves. You need a common object to synchronize on.
I would recommend that you synchronize on the list itself. It will mean that any instances that are contending for the same list are blocked on each other and any threads that are not, will not be blocked. Your add and remove methods should be:
public void add(String name) {
synchronized (name) {
names.add(name);
}
}
public String removeFirst() {
synchronized (name) {
if (names.size() > 0)
return (String) names.remove(0);
else
return null;
}
}
In general:
1) Since you are creating a new instance of your class each time, you basically have no "common" object for all threads to to lock upon. You should define something like:
static final Object lock = new Object();
and synchronize on this object instead.
2) IMHO it's preferable to implement Runnable rather than extending Thread.
Even though you are using Collections.synchronizedList there is a race condition that exists in your code.
Below is the example of the race codition inside your code.
lock(NameDropper[0]) lock(NameDropper[1])
names.size() > 0 is true names.size() > 0 is true
names.remove(0)
names.remove(0) <--- Error here.
Since you are creating NameDropper instance for each thread which shares single instance of List you have this race condition.
What you can do is create separate list for each NameDropper
List l1 = Collections.synchronizedList(new LinkedList());
t[i - 1] = new NameDropper(l1);
This way each NameDropper will have its own instance of List.
As others have stated, NameList is not being shared. Here is one way with minimal recoding to fix your code (there are others):
Change the constructor to take a NameList (not List).
public NameDropper(NameList list) {
this.n1 = list;
}
Create the NameList where you are currently creating the List.
NameList l = new NameList(Collections.synchronizedList(new LinkedList()));
Related
I am not sure how to convert a function I've written so that it will run as multiple threads concurrently in Java.
The function takes a root, which will be different for each thread that "splits off" at a given junction point (the if statement for this is within the function, each newly-created thread should be able to split off in the future as well, at the next junction).
I want all threads to die once they reach the target, but the "while" loop for checking whether they've reached the end is also within the function.
Basically, I want the function to be able to run multiple times concurrently, with a modified starting point each time, and for the "original" thread to be killed off before splitting.
I also can't extend Thread because I'm already extending another class, so I'm trying to do it by implementing Runnable.
Here is the class (the parent classes work fine so I don't think I need to post them):
public class Multithreaded extends ParentClass implements Runnable {
#Override
public void run() {
executeThread(modelThreaded, new HashMap<>());
}
private final Set<Tile> VISITED = new HashSet<>();
private Grid modelThreaded; //to be able to update the root?
public Multithreaded() {
super();
}
#Override
protected int runPathfinder(Grid model, List<Tile> path) {
HashMap<Tile, Integer> tileData = new HashMap<>();
this.modelThreaded = model;
this.executeThread(model, tileData);
int cost = tileData.get(model.getTarget()) - 1;
this.statistics.setPathFound(true, cost);
this.painter.drawPath(path, model);
return cost;
}
private void executeThread(Grid model, HashMap<Tile, Integer> tileData) {
// Keeps track of visited tiles
VISITED.add(model.getRoot());
//start at the root
Tile currentTile = model.getRoot();
List<Tile> posNeighbors = model.getTileNeighbors(currentTile);
List<Tile> validNeighbors = new ArrayList<>();
int DEFAULT_DISTANCE = 1;
tileData.put(model.getRoot(), DEFAULT_DISTANCE);
int iteration = 0;
while (!isVisited(model.getTarget())) {
iteration++;
posNeighbors.clear();
validNeighbors.clear();
posNeighbors = model.getTileNeighbors(currentTile);
validNeighbors = getForward(posNeighbors);
//debugging
System.out.println("Valid Neighbors for currentTile ("
+ currentTile.getX() + ", " + currentTile.getY() + "): ");
for (Tile validNeighbor : validNeighbors) {
System.out.println(validNeighbor.getX() + ", " + validNeighbor.getY());
}
// tries to split along junctions into multithreads
// tries to kill mouse if there's a dead end
if (validNeighbors.size() > 0) {
for (Tile validNeighbor : validNeighbors) {
currentTile = validNeighbor;
// want to create a new thread for each validNeighbor here, but with
// a small change: the root changes to the current validNeighbor
model.setRoot(validNeighbor);
Runnable runnable = new Multithreaded();
Thread thread = new Thread(runnable);
thread.start();
}
}
//attempt to kill/stop current thread if there are no more options left for that thread
else {
break;
}
VISITED.add(currentTile);
tileData.put(currentTile, DEFAULT_DISTANCE + iteration);
}
private List<Tile> getForward(List<Tile> posNeighbors) {
List<Tile> validNeighbors = new ArrayList<>();
for (Tile posNeighbor : posNeighbors) {
if (posNeighbor != null && !posNeighbor.isWall()
&& !isVisited(posNeighbor)) {
validNeighbors.add(posNeighbor);
}
}
return validNeighbors;
}
private boolean isVisited(Tile posNeighbor) {
for (Tile visitedTile : VISITED) {
if (visitedTile == posNeighbor) {
return true;
}
}
return false;
}
}
As you can see, I want the threads to keep going unless:
one of them encounters the target (model.getTarget()) or
it reaches a point where there are 0 validNeighbors.
When there's 1 validNeighbor for a thread, it should stay singular and proceed along that path until it either reaches another junction or a dead end (getForward returns only the unvisited neighbors)
So, when a thread encounters a junction (2 validNeighbors), it should split into two and kill the original thread (stopping its execution of executeThread, which is why I put a break in there), with one thread for each direction, and continue running the algorithm. With my current code, it runs down the path correctly, but doesn't split into different threads and doesn't stop running when it encounters a dead end.
What would be the best way to get this to run? Am I correct in putting executeThread() in run(), or is there somewhere else I should be putting it? I've tried just doing runnable.run() instead of Thread thread and thread.start(), but that doesn't seem to help. I'm really not sure what to do here, I feel like I'm missing something obvious...
EDIT: runPathfinder is the function called by the parent classes in order for all of this code to run
I think the following mre(1) reproduces the multi-threading functionality required.
Each node (state / tile) is represented by an integer.
getTileNeighbors returns 3 random neighbors.
All thread share a synchronized visited collection, and should stop after target was added to visited.
(copy-paste the entire code to Main.java and run)
import java.util.*;
public class Main {
public static void main(String[] args) {
new Thread(new Multithreaded(0, 20)).start();
}
}
class Multithreaded implements Runnable {
// Synchronized Set (shared between threads)
private static final Set<Integer> visited = Collections.synchronizedSet(new HashSet<Integer>());
private final int root, target;
//root and target assumed >=0
public Multithreaded(int root, int target) {
this.root = root;
this.target = target;
}
#Override
public void run() {
executeThread(root);
}
private void executeThread(int root) {
visited.add(root);
System.out.println("New thread, root="+ root);
while (!isStopConditionMet()) {
List<Integer> neighbors = getTileNeighbors(root);
//todo if neighbors is empty break out of the while loop
for (Integer neighbor : neighbors) {
if(! visited.add(neighbor)) {
continue; //skip is already visited
}
Runnable runnable = new Multithreaded(neighbor, target);
Thread thread = new Thread(runnable);
thread.start();
}
}
}
//returns a list o 3 random numbers between 0-target (inclusive)
//to represent 3 random neighbors
private List<Integer> getTileNeighbors(int currentTile) {
Random rnd = new Random();
int maxValue = target +1;
return Arrays.asList(rnd.nextInt(maxValue), rnd.nextInt(maxValue), rnd.nextInt(maxValue));
}
private boolean isStopConditionMet() {
return visited.contains(target);
}
}
(1) mre should demonstrate the problem to be solved, and not a specific application.
I'm new to this site, so please feel free to correct me if there's anything wrong about my question or the style of the question.
I need to implement the Iterable Interface in my ShareCollection class, so that I can iterate over all the shares in this class. When I'm testing my class with the sample data it always hands back '0' as size, even though there are (in my example) two shares in my collection.
Here's the code of the class + one sample method which hands back an error:
public class ShareCollection implements Iterable<Share>{
private HashSet<Share> shares;
public ShareCollection() {
this.shares = new HashSet<Share>();
}
public ShareCollection(Collection<Share> shares) {
for (Share s : shares) {
HashSet<Share> checkSet = new HashSet<Share>(shares);
checkSet.remove(s);
if (checkSet.contains(s)) {
throw new IllegalArgumentException("There can't be two shares with the same name!");
}
}
this.shares = new HashSet<Share>(shares);
}
public boolean add(Share share) {
if (share == null) {
throw new NullPointerException("share isnt allowed to be null!");
}
return shares.add(share);
}
#Override
public Iterator<Share> iterator() {
return new HashSet<Share>(shares).iterator();
}
}
Here's the main method with the sample data I'm using:
public static void main(String[] args) {
Share s1 = new Share("s1", new ArrayList<>());
Share s2 = new Share("s2", new ArrayList<>());
ShareCollection sc = new ShareCollection()
sc.add(s1);
sc.add(s2);
int counter = 0;
for (Share s : sc) {
counter++;
}
System.out.print("Counter: " + counter + "\n");
System.out.print("Size: " + sc.size());
}
Here's the output for the main-method:
Counter: 2
Size: 0
Here's the error for the 'add'-method:
java.lang.AssertionError: ShareCollection#size should give 1 for a collection with 1 elements.
Expected: <1>
but: was <0>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at jpp.marketanalysis.tests.data.TestShareCollection.hasElements(TestShareCollection.java:158)
at jpp.marketanalysis.tests.data.TestShareCollection.testAdd(TestShareCollection.java:55)
Thank you in advance for your answers!
Update:
Exchanged the ArrayList with a HashSet (see #SeanPatrickFloyd's first answer)
Possible error: Does your Share class override the .equals() method?
Because ArrayList.contains() delegates to .equals()
Also, I see at least two problems with your code:
An ArrayList is very bad at a .contains() lookup (O(n)). You should use a HashSet instead (in that case you'd need to override both .equals() and .hashCode() in your Share class), it gives you O(1) and handles the .add() method properly for you as well
The Iterator you are returning is the ArrayList's original iterator, which makes your code vulnerable in several ways, including ConcurrentModificationException if you add something while iterating, but also mutation, if someone calls .remove() on the iterator. I'd suggest you make a defensive copy of the collection and use that iterator.
Here's your code rewritten accordingly:
public class ShareCollection implements Iterable<Share>{
private final Set<Share> shares;
public ShareCollection() {
this.shares = new HashSet<>();
}
public ShareCollection(Collection<Share> shares) {
this.shares = new HashSet<>(shares);
}
public boolean add(Share share) {
if (share == null) {
throw new NullPointerException("share isnt allowed to be null!");
}
return shares.add(share);
}
#Override
public Iterator<Share> iterator() {
return new HashSet<>(shares).iterator();
}
}
I've already made another question close to this one several minutes ago, and there were good answers, but it was not what I was looking for, so I tried to be a bit clearer.
Let's say I have a list of Thread in a class :
class Network {
private List<Thread> tArray = new ArrayList<Thread>();
private List<ObjectInputStream> input = new ArrayList<ObjectInputStream>();
private void aMethod() {
for(int i = 0; i < 10; i++) {
Runnable r = new Runnable() {
public void run() {
try {
String received = (String) input.get(****).readObject(); // I don't know what to put here instead of the ****
showReceived(received); // random method in Network class
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
tArray.add(new Thread(r));
tArray.get(i).start();
}
}
}
What should I put instead of ** ?
The first thread of the tArray list must only access the first input of the input list for example.
EDIT : Let's assume my input list has already 10 elements
It would work if you put i. You also need to add an ObjectInputStream to the list for each thread. I recommend you use input.add for that purpose. You also need to fill the tArray list with some threads, use add again there.
Here's the solution:
private void aMethod() {
for(int i = 0; i < 10; i++) {
final int index = i; // Captures the value of i in a final varialbe.
Runnable r = new Runnable() {
public void run() {
try {
String received = input.get(index).readObject().toString(); // Use te final variable to access the list.
showReceived(received); // random method in Network class
} catch (Exception exception) {
exception.printStackTrace();
}
}
};
tArray.add(new Thread(r));
tArray.get(i).start();
}
}
As you want each thread to access one element from the input array you can use the value of the i variable as an index into the list. The problem with using i directly is that an inner class cannot access non-final variables from the enclosing scope. To overcome this we assign i to a final variable index. Being final index is accessible by the code of your Runnable.
Additional fixes:
readObject().toString()
catch(Exception exception)
tArray.add(new Thread(r))
How can I make sure the print out order same as the order in the original array, when two threads are used? I want it printing '0 1 2 3 4 5 6 7 8 9', but currently the order is not guaranteed. Any way to make it in order? Thank you a lot.
public class Test {
public static void main(String[] args){
DataStore dataStore = new DataStore();
for(int i=0; i<10; i++){
dataStore.add(String.valueOf(i));
}
CopyThread t1 = new CopyThread(dataStore);
CopyThread t2 = new CopyThread(dataStore);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch(Throwable t) {
}
}
}
class CopyThread extends Thread {
private DataStore data;
public CopyThread(DataStore data){
this.data = data;
}
public void run(){
DataStore.Line line = null;
int lineID;
while( (line = data.getLine()) != null ){
lineID = line.id;
System.out.println(Thread.currentThread().getName() + ": " + lineID);
}
}
}
class DataStore {
ArrayList<String> lines = new ArrayList<String>();
int current = 0;
public synchronized Line getLine () {
if (current >= lines.size()) {
return null;
}
Line line = new Line(lines.get(current), current);
current++;
return line;
}
public synchronized void add (String s) {
lines.add(s);
}
public synchronized int size () {
return lines.size();
}
public static class Line {
public String line;
public int id;
public Line (String str, int i) {
line = str;
id = i;
}
}
}
Try Vector instead of ArrayList .
Vector
The Vector class implements a growable array of objects. Like an
array, it contains components that can be accessed using an integer
index. However, the size of a Vector can grow or shrink as needed to
accommodate adding and removing items after the Vector has been
created.
Each vector tries to optimize storage management by maintaining a
capacity and a capacityIncrement. The capacity is always at least as
large as the vector size; it is usually larger because as components
are added to the vector, the vector's storage increases in chunks the
size of capacityIncrement. An application can increase the capacity of
a vector before inserting a large number of components; this reduces
the amount of incremental reallocation.
The Iterators returned by Vector's iterator and listIterator methods
are fail-fast: if the Vector is structurally modified at any time
after the Iterator is created, in any way except through the
Iterator's own remove or add methods, the Iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the Iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future. The Enumerations returned by Vector's elements method
are not fail-fast.
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification. Fail-fast
iterators throw ConcurrentModificationException on a best-effort
basis. Therefore, it would be wrong to write a program that depended
on this exception for its correctness: the fail-fast behavior of
iterators should be used only to detect bugs.
You can use synchronize to achieve that:
synchronized(data) {
while( (line = data.getLine()) != null ){
lineID = line.id;
System.out.println(Thread.currentThread().getName() + ": " + lineID);
}
}
I have LinkedList of objects and an iterator. I know that this ConcurrentModificationException is thrown when you try to modify the list while running the iterator. But in my case, I don't understand where this modification is being done.
The iterator looks like this :
private static void insertTasks(Task t) {
if(eventQueue.size() == 0) {
eventQueue.addFirst(tsk);
return;
}
int pos = 0;
while (itr.hasNext()){
//The line below throws the exception
if (t.getArrivalTime() <= itr.next().getArrivalTime() )
{
break;
}
pos++;
}
}
I am calling this insertTasks method from another method as shown below :
tsk = null;
tsk = new Task(1,"P1",1,4.0f,1.5f,0.0f,8.0f);
insertTasks(tsk);
tsk = null;
tsk = new Task(0,"P0",2,5.0f,2.5f,1.0f,10.0f);
insertTasks(tsk);
The getArrivalTime in the Task objects looks like :
public float getArrivalTime() { return arrivalTime; }
My question is, where am I doing this modification ? The while loop where I run this iterator is not doing any modification. Does it ?
Am I missing something ?
I reckon the problem is that itr is a static field in your class and that's creating the issue, as you're adding an element to eventQueue in your second call to insertTasks().
Avoid static fields... program yourself to fear them and avoid them as much as you can :). They evil, and OO unfriendly.