简体   繁体   中英

Java thread is not interrupting

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?

  • When I run the program as it is implemented here, Only a few of all the fractal elements are shown in the GUI. However, once a lot of edges have to be calculated, fewer and fewer of them are displayed in the gui. Using the debugger I can see that all the edges have been calculated, but application.requestDrawEdges(); was called before all edges are calculated.
  • When I run the program without the delay in the 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM