线程只是停止工作Java



我正在编写一个非常简单的模拟,应该在wxh板上更改场颜色。板上的每个字段都是一个线程,每随机几毫秒更改其颜色。问题是,一段时间后它就会停止变化。我的代码有问题,还是优化问题,还是其他问题?是某种僵局吗?(线程量不会改变任何东西,只是停止后的时间,调试板是 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();
}

你得到的是一个典型的死锁。

考虑两个Fields A 在 x=0、y=0 和 B 在 x=1、y=0 时的情况。

在某个时间点,FieldA 尝试计算averageColor()- 在此期间它保持锁定状态(因为averageColor()是同步的(。此计算的一部分是在 BField上调用getColor(..),该FieldB 上同步。

如果同时FieldB试图计算其averageColor()FieldB对自己持有一个锁(所以FieldA不能在FieldB上调用getColor(..)(。此计算的一部分反过来是在 AField上调用getColor(..)- 由于 AFieldA 本身持有一个锁并尝试在 BField上调用getColor(..),因此阻塞。

只是几件事:

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

二.导致run循环退出的异常。我怀疑情况是否如此,但您可能希望在调试时捕获所有错误。

一般来说,Swing 不是线程安全的。对 Swing 组件方法的任何调用都必须在事件调度线程上完成。您可以在 Java 教程"事件调度线程"中阅读有关它的信息:https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html

感谢@cmosher01

getColorgetSideColoraverageColor中删除synchronized解决了问题,但我真的不明白为什么。如果有人知道,我将不胜感激,为什么它可能导致问题。

最新更新