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.
Related
I'm trying to implement a bfs algorithm in Java,but it doesn't work as it should be.
I've made a game map comprised of HexTile objects(custom objects,similar to matrix elements). Each HexTile includes one adjacency list containing references to the elements that it's connected to, one function that returns those elements and one function that computes the distance between two HexTiles. The bfs algorithm is excecuted in another class called unit(units are placed in HexTiles) and finds every unit available in a given range from the room(currentTile). It then creates an ArrayList with the given units.
class HexTile {
static final int MAX_NEIGHBOURS = 6;
private HexTile[] neighbours;
public HexTile[] getNeighbours() {
return this.neighbours;
}
public double distanceFromTarget(HexTile target) {
double distance = Math.sqrt(Math.pow((this.getRow() - target.getRow()), 2) + Math.pow((this.getCol() - target.getCol()), 2));
return distance;
}
}
class Unit {
private ArrayList<Unit> unitsWithinRange = new ArrayList<Unit>();
private void findUnitsWithinRange(HexTile currentTile, int attackRange) {
Queue<HexTile> queue = new LinkedList<>();
ArrayList<HexTile> visited = new ArrayList<HexTile>();
queue.add(currentTile);
visited.add(currentTile);
while (!queue.isEmpty()) {
HexTile aux = queue.poll();
for (HexTile auxNeigh : aux.getNeighbours()) {
if (auxNeigh != null && (!visited.contains(auxNeigh))) {
visited.add(auxNeigh);
queue.add(auxNeigh);
}
}
if (aux != null && (currentTile.distanceFromTarget(aux) <= attackRange)) {
Unit auxUnit = aux.getUnitOnTile();
this.unitsWithinRange.add(auxUnit);
}
}
queue.clear();
visited.clear();
}
}
What happens whenever findUnitsWithinRange is excecuted is that it return a list of units,but the units that are in range 1 are not included(direct neighbours to root).Sometimes the program crashes,because units need to be able to know if there are any nearby units,to excecute some other functions.Any advice would be appreciated!
I have a Hashmap that is created for each "mailer" class and each "agent" class creates a mailer.
My problem is that each of my "agents" creates a "mailer" that in turn creates a new hashmap.
What I'm trying to do is to create one Hashmap that will be used by all the agents(every agent is a thread).
This is the Agent class:
public class Agent implements Runnable {
private int id;
private int n;
private Mailer mailer;
private static int counter;
private List<Integer> received = new ArrayList<Integer>();
#Override
public void run() {
System.out.println("Thread has started");
n = 10;
if (counter < n - 1) {
this.id = ThreadLocalRandom.current().nextInt(0, n + 1);
counter++;
}
Message m = new Message(this.id, this.id);
this.mailer.getMap().put(this.id, new ArrayList<Message>());
System.out.println(this.mailer.getMap());
for (int i = 0; i < n; i++) {
if (i == this.id) {
continue;
}
this.mailer.send(i, m);
}
for (int i = 0; i < n; i++) {
if (i == this.id) {
continue;
}
if (this.mailer.getMap().get(i) == null) {
continue;
} else {
this.received.add(this.mailer.readOne(this.id).getContent());
}
}
System.out.println(this.id + "" + this.received);
}
}
This is the Mailer class :
public class Mailer {
private HashMap<Integer, List<Message>> map = new HashMap<>();
public void send(int receiver, Message m) {
synchronized (map) {
while (this.map.get(receiver) == null) {
this.map.get(receiver);
}
if (this.map.get(receiver) == null) {
} else {
map.get(receiver).add(m);
}
}
}
public Message readOne(int receiver) {
synchronized (map) {
if (this.map.get(receiver) == null) {
return null;
} else if (this.map.get(receiver).size() == 0) {
return null;
} else {
Message m = this.map.get(receiver).get(0);
this.map.get(receiver).remove(0);
return m;
}
}
}
public HashMap<Integer, List<Message>> getMap() {
synchronized (map) {
return map;
}
}
}
I have tried so far :
Creating the mailer object inside the run method in agent.
Going by the idea (based on your own answer to this question) that you made the map static, you've made 2 mistakes.
do not use static
static means there is one map for the entire JVM you run this on. This is not actually a good thing: Now you can't create separate mailers on one JVM in the future, and you've made it hard to test stuff.
You want something else: A way to group a bunch of mailer threads together (these are all mailers for the agent), but a bit more discerning than a simple: "ALL mailers in the ENTIRE system are all the one mailer for the one agent that will ever run".
A trivial way to do this is to pass the map in as argument. Alternatively, have the map be part of the agent, and pass the agent to the mailer constructor, and have the mailer ask the agent for the map every time.
this is not thread safe
Thread safety is a crucial concept to get right, because the failure mode if you get it wrong is extremely annoying: It may or may not work, and the JVM is free to base whether it'll work right this moment or won't work on the phase of the moon or the flip of a coin: The JVM is given room to do whatever it feels like it needs to, in order to have a JVM that can make full use of the CPU's powers regardless of which CPU and operating system your app is running on.
Your code is not thread safe.
In any given moment, if 2 threads are both referring to the same field, you've got a problem: You need to ensure that this is done 'safely', and the compiler nor the runtime will throw errors if you fail to do this, but you will get bizarre behaviour because the JVM is free to give you caches, refuse to synchronize things, make ghosts of data appear, and more.
In this case the fix is near-trivial: Use java.util.concurrent.ConcurrentHashMap instead, that's all you'd have to do to make this safe.
Whenever you're interacting with a field that doesn't have a convenient 'typesafe' type, or you're messing with the field itself (one thread assigns a new value to the field, another reads it - you don't do that here, there is just the one field that always points at the same map, but you're messing with the map) - you need to use synchronized and/or volatile and/or locks from the java.util.concurrent package and in general it gets very complicated. Concurrent programming is hard.
I was able to solve this by changing the mailer to static in the Agent class
I am using a canvas, moving objects on the screen, when an object hit the left side of the canvas (x=0), another object of the same type gets instantiated, and start moving on the screen.
Everything works fine, a few objects gets created and start moving around the screen.
At a certain point, I receive a concurrent modification exception in my run method where the game loop is, where gameObjs is an ArrayList:
#Override
public void run() {
while(isRunning){
if(!myHolder.getSurface().isValid())
continue;
Canvas canvas = myHolder.lockCanvas();
canvas.drawRect(0,0,canvas.getWidth(), canvas.getHeight(), pWhite);
for(MyGameObject gameObj : gameObjs){
gameObj.move(canvas);
}
myHolder.unlockCanvasAndPost(canvas);
}
}
I've tried to use an Iterator, but still getting the same error.
I really appreciate your help. Thank you in advance!
Collections.synchronizedList(...) won't work if something like this is happening... (throws a ConcurrentModificationException...)
public class ConcurrentTest {
public static void main(String[] args) {
List<String> things = new ArrayList<>();
Runnable modifyThread = () -> {
while(true) {
for(int k = 0; k < 1000; k++) {
things.add(String.valueOf(k));
}
while(!things.isEmpty()) {
things.remove(0);
}
}
};
Runnable readThread = () -> {
while(true) {
for(String thing : Collections.synchronizedList(things)) {
System.out.println(thing);
}
}
};
new Thread(modifyThread).start();
new Thread(readThread).start();
}
}
Try and find other places in your code where this list is being modified. There must be another thread manipulating the collection while you are iterating through it.
You could take a copy of the list before iterating over it.
For example, in the code above, try...
for(String thing : new ArrayList<>(things)) {
...instead of...
for(String thing : Collections.synchronizedList(things)) {
...and you will no longer get an exception (but this still won't be "correct", if you run it, you will see loads of nulls being printed out...)
Even better, keep the read loop as...
for(String thing : things) {
...but change the type of list...
List<String> things = new CopyOnWriteArrayList<>();
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()));
This is my code. As you see in the run method, I assign values to tStart, tEnd, tAround and wTime. But when the Thread ends, they still have the default values of -1. I try printing out their values while the run() is running, and I have the correct values. But they are not 'writing' those values back to the variables when the thread ends.
public class PCB extends Thread{
public int id, arrivalTime, cpuBurst, ioBurst;
public int tStart, tEnd, tAround, wTime;
public PCB(){
id = -1;
arrivalTime = -1;
cpuBurst = -1;
ioBurst = -1;
tStart = -1;
tEnd = -1;
tAround = -1;
wTime = -1;
}
public void run(){
try{
.........
//calculation for FCFS
if (id == 1){ //special case for the first one
tStart = arrivalTime;
}
else tStart = lastEndTime;
tEnd = tStart + cpuBurst + ioBurst;
tAround = tEnd - arrivalTime;
wTime = tStart - arrivalTime;
PCBThreadStopFlag = true;
}
catch(InterruptedException e){
e.printStackTrace();
}
}
}
When the thread ends, this is how I print out the values:
// now we print out the process table
String format = "|P%1$-10s|%2$-10s|%3$-10s|%4$-10s|%5$-10s|%6$-10s|%7$-10s|%8$-10s|\n";
System.out.format(format, "ID", "ArrTime", "CPUBurst", "I/OBurst", "TimeStart", "TimeEnd","TurnAround","WaitTime");
ListIterator<PCB> iter = resultQueue.listIterator();
while(iter.hasNext()){
PCB temp = iter.next();
System.out.format(format, temp.id, temp.arrivalTime, temp.cpuBurst, temp.ioBurst, temp.tStart, temp.tEnd, temp.tAround, temp.wTime );
}
And here is how I waited for the thread to stop first:
while(!rq.values.isEmpty()){
//System.out.println("Ready queue capacity now: " + rq.values.size());
currentProcess = new PCB(rq.values.getFirst());
currentProcess.start();
while(PCBThreadStopFlag == false) {}
//currentProcess.stop();
PCBThreadStopFlag = false;
//after everything is done, remove the first pcb
// and add it to the result queue (just to print the report)
resultQueue.addLast(rq.values.removeFirst());
}
I use the flag PCBThreadStopFlag in the run() up top (at the end when all the assignments are done) then in this function, I use while(PCBThreadStopFlag == false) {} to do the "busy-wait" task. may be this is the cause??
This is just a guess, but I'll bet you're not joining on the threads before you print the results. In other words I suspect you're starting the threads and then immediately printing the result without waiting for the threads to complete.
EDIT: OK, try this...
Idea #1: Declare the PCBThreadStopFlag as volatile, and try again. Tell us if that works.
Idea #2: Get rid of the whole stop flag thing altogether, and replace the busy wait with
currentProcess.join();
and tell us if that works.