线程只是停止工作Java

时间:2018-05-02 19:48:17

标签: java multithreading deadlock

我正在编写一个非常简单的模拟,它应该改变w x h板上的字段颜色。电路板上的每个字段都是一个线程,每隔一个毫秒就会改变它的颜色。问题是,经过一段时间后它就会停止变化。我的代码有什么问题,或者是最优化的东西,还是别的东西?这是某种僵局吗? (线程数量不会改变任何东西,只是停止后的时间,调试板是25x25)

我还发现averageColor()可能会导致问题,因为没有它就可以正常工作(例如静态颜色而不是平均颜色)

public void run() {
    while( true ) {
        try {
            int time;
            double q;
            int newcolor;
            synchronized( gen ) { // gen is a Random (one for the whole program)
                time = gen.nextInt( k ) + k/2; // k is a given parameter, 200 for debugging
                q = gen.nextDouble();
                newcolor = gen.nextInt( 256*256*256 );
            }
            synchronized( this ) { // posting rest of the class below
                wait( time ); // replacing with Thread.sleep( time ) does not fix the problem
                if( q < p ) { // with p probability it changes color to rando
                    me.setBackground( new Color( newcolor ) );
                }
                else { // with p-1 it pick an avarge
                    me.setBackground( averageColor() ); // averageColor takes an avarge of neighbour fields
                }
            }
            //Thread.yield(); // removed it as wrestang said, but it does not change anything
        } catch( InterruptedException e ) {
            e.printStackTrace();
        }
    }
}

其他课程:

public class Field extends Thread {

static Panel panel;
Label me;
Random gen;
int x, y, w, h;
int k;
double p;
Field[][] others;

enum Side {
    up,
    down,
    right,
    left
}

enum ColorPart {
    R,
    G,
    B
}

Field( Panel panel, Random gen, Field[][] others, int x, int y, int k, double p, int w, int h ) {
    this.gen = gen;
    this.others = others;
    this.x = x;
    this.y = y;
    this.k = k;
    this.p = p;
    this.w= w;
    this.h = h;

    me = new Label();
    me.setBackground( new Color( gen.nextInt( 256*256*256 ) ) );
    panel.add( me );

    setDaemon( true );
}

synchronized int getColor( ColorPart c ) {
    switch( c ) {
    case B:
        return me.getBackground().getBlue();
    case G:
        return me.getBackground().getGreen();
    case R:
        return me.getBackground().getRed();
    }
    return 0;
}

synchronized int getSideColor( Side side, ColorPart c ) {
    int a, b;
    switch( side ) {
    case down:
        b = y+1;
        while( b >= h ) b -= h;
        return others[x][b].getColor( c );
    case left:
        a = x-1;
        while( a < 0 ) a += w;
        return others[a][y].getColor( c );
    case right:
        a = x+1;
        while( a >= w ) a -= w;
        return others[a][y].getColor( c );
    case up:
        b = y-1;
        while( b < 0 ) b += h;
        return others[x][b].getColor( c );
    }
    return 0;
}

synchronized Color averageColor() {
    int r = 0;
    int g = 0;
    int b = 0;

    r += getSideColor( Side.up, ColorPart.R );
    r += getSideColor( Side.down, ColorPart.R );
    r += getSideColor( Side.right, ColorPart.R );
    r += getSideColor( Side.left, ColorPart.R );
    r /= 4;

    g += getSideColor( Side.up, ColorPart.G );
    g += getSideColor( Side.down, ColorPart.G );
    g += getSideColor( Side.right, ColorPart.G );
    g += getSideColor( Side.left, ColorPart.G );
    g /= 4;

    b += getSideColor( Side.up, ColorPart.B );
    b += getSideColor( Side.down, ColorPart.B );
    b += getSideColor( Side.right, ColorPart.B );
    b += getSideColor( Side.left, ColorPart.B );
    b /= 4;

    return new Color( r, g, b );
}

@Override
public void run() {
    while( true ) {
        try {
            int time;
            double q;
            int newcolor;
            synchronized( gen ) {
                time = gen.nextInt( k ) + k/2;
                q = gen.nextDouble();
                newcolor = gen.nextInt( 256*256*256 );
            }
            synchronized( this ) {
                wait( time );
                if( q < p ) {
                    me.setBackground( new Color( newcolor ) );
                }
                else {
                    me.setBackground( averageColor() );
                }
            }
        } catch( InterruptedException e ) {
            e.printStackTrace();
        }
    }
}

}

创建并开始于:

public class SymPanel extends Panel {
private static final long serialVersionUID = 1L;

Random gen;
int w, h;
int k;
double p;
Field[][] fields;

SymPanel( int w, int h, int k, double p ) {
    this.w = w;
    this.h = h;
    this.k = k;
    this.p = p;

    setLayout( new GridLayout( h, w ) );

    gen = new Random();

    Field.panel = this;

    fields = new Field[w][h];
    for( int j = 0; j<h; j++ ) {
        for( int i = 0; i<w; i++ ) {
            fields[i][j] = new Field( this, gen, fields, i, j, k, p, w, h );
        }
    }
}

public synchronized void start() {
    for( int j = 0; j<h; j++ ) {
        for( int i = 0; i<w; i++ ) {
            fields[i][j].start();
        }
    }
}

}

主要:

public static void main( String[] args ) {
    frame = new Frame("Sym");
    frame.setBounds( 300, 100, 1024, 768 );
    frame.addWindowListener( new Sym() );

    sympanel = new SymPanel( 25, 25, 200, 0.3 );
    frame.add( sympanel );

    frame.setVisible( true );

    sympanel.start();
}

4 个答案:

答案 0 :(得分:0)

只是一些事情:

一个。当上面代码中的q超过(或匹配)p的值时,代码将计算平均颜色 - 每次都相同,假设相邻字段没有更改颜色。

B中。导致run循环退出的异常。我怀疑是这种情况,但您可能希望在调试时捕获所有错误。

答案 1 :(得分:0)

通常,Swing不是线程安全的。必须在事件派发线程上完成对Swing组件方法的任何调用。您可以在Java Tutorials&#34; The Event Dispatch Thread&#34;:https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html

中阅读相关内容。

答案 2 :(得分:0)

感谢@ cmosher01

synchronized getColorgetSideColor移除averageColor来解决问题,但我不知道为什么。如果有人知道,我会理解为什么它可能导致了这个问题。

答案 3 :(得分:0)

你得到的是典型的僵局。

考虑两个Field的情况,在x = 0,y = 0,B在x = 1,y = 0。

Field A尝试计算averageColor()的某个时间点 - 在此期间它会自行锁定(因为averageColor()已同步)。此计算的一部分是在getColor(..) B上调用Field,并在Field B上同步。

如果同时Field B尝试计算其averageColor()Field B会自行锁定(Field A无法调用getColor(..)Field B)。此计算的一部分依次在getColor(..) A上调用Field - 因为Field A保持对自身的锁定并尝试在{{1上调用getColor(..) B。