I am working on a Java program using threads and I keep getting into some issues and I hope someone could help me figure this out here.
It is a project for school and we have to make some Koch fractals.
The first class is a manager. This is where the threads are created to generate the edges for the Koch fractal using an EdgeGenerator.
import java.util.logging.Level;
import java.util.logging.Logger;
import uckochfractalfx.UCKochFractalFX;
public class KochManager {
private final UCKochFractalFX application;
private final IEdgeCollection edges;
private int level;
private int count;
public KochManager(UCKochFractalFX application) {
this.application = application;
this.edges = new EdgeArrayList();
}
public synchronized void changeLevel(int nxt){
this.level = nxt;
this.count = 0;
this.edges.clear();
EdgeGenerator left, right, bottom;
left = new EdgeGenerator(this, EdgeLocation.LEFT);
right = new EdgeGenerator(this, EdgeLocation.RIGHT);
bottom = new EdgeGenerator(this, EdgeLocation.BOTTOM);
Thread tLeft, tRight, tBottom;
tLeft = new Thread(left);
tRight = new Thread(right);
tBottom = new Thread(bottom);
tLeft.start();
tRight.start();
tBottom.start();
try {
tLeft.join(500);
tRight.join(500);
tBottom.join(500);
} catch (InterruptedException ex) {
Logger.getLogger(KochManager.class.getName()).log(Level.SEVERE, null, ex);
}
application.requestDrawEdges();
}
public void addEdge(Edge edge){
this.edges.add(edge);
}
public synchronized void increaseCount(){
count ++;
}
public int getLevel() {
return level;
}
}
The second class is the EdgeGenerator which implements Runnable and Observer.
The observable is the KochFractal class (which is not included here). The update method is called on the generate__Edge() methods of KochFractal. This all works just fine and is tested without using threads and with threads.
import java.util.Observable;
import java.util.Observer;
public class EdgeGenerator implements Runnable, Observer {
private final KochManager kochManager;
private final EdgeLocation edgeLocation;
private final KochFractal koch;
public EdgeGenerator(KochManager kochManager, EdgeLocation edgeLocation) {
this.kochManager = kochManager;
this.edgeLocation = edgeLocation;
this.koch = new KochFractal();
this.koch.addObserver(this);
}
@Override
public void run() {
koch.setLevel(kochManager.getLevel());
switch (this.edgeLocation) {
case LEFT:
this.koch.generateLeftEdge();
break;
case RIGHT:
this.koch.generateRightEdge();
break;
case BOTTOM:
this.koch.generateBottomEdge();
break;
}
Thread.currentThread().interrupt();
}
@Override
public void update(Observable o, Object o1) {
this.kochManager.addEdge((Edge)o1);
this.kochManager.increaseCount();
}
}
The last class here is the collection class that uses an ArrayList. On add and remove I have used the synchronized keyword. It is my understanding that this makes the instance methods accessable to only one thread at a time and puts the other threads on hold.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class EdgeArrayList implements IEdgeCollection{
private final List<Edge> edges;
public EdgeArrayList() {
this.edges = new ArrayList<>();
}
@Override
public synchronized void add(Edge e) {
edges.add(e);
}
@Override
public synchronized void remove(Edge e) {
edges.remove(e);
}
@Override
public void clear() {
edges.clear();
}
@Override
public List<Edge> getAll() {
return Collections.unmodifiableList(edges);
}
}
So what is going on here?
application.requestDrawEdges();
was called before all edges are calculated. join()
methods it just keeps running and not displaying the gui. As far as I know Thread.currentThread().interrupt();
should stop the current thread and call the join()
method, but that is not happening.
I hope someone can put me in the right direction here.
Your understanding of join is wrong.
Your main thread will simply wait those 500 ms for each subterranean to join... but if that doesn't happen, code execution just continues. In other words: after about 1.5 seconds drawing will start.
Instead of using the low level primitive join, you could have each subthread actively announce "I am done" instead. And your main thread just waits for all subthreads to do that.
And beyond that: thread objects are pretty "expensive". You really should not throw them away after each iteration. Instead: look into using an ExecutorService instead. You create one service initially, to then just push new tasks into that service. Together with Futures that should allow for a more elegant solution. And as Hovercraft suggests, you could also allow the ui to be updated more often.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.