0

我尝试重新启动线程,但线程中的同步块在重新启动后保持锁定。我不应该更改套接字属性,因为某些进程花费的时间太长,但是当网络连接丢失时,它会永远挂起。我尝试使用 InterruptedException 但它不起作用。有没有办法释放这个锁?

public static void main(String[] args) {
    try {
        synchronizedBlock t1 = new synchronizedBlock();
        t1.start();
        Thread.sleep(500);
        t1.cancel();
        t1 = new synchronizedBlock();
        t1.start();
    } catch (Exception e) {
        e.printStackTrace();
    }
    while (true) {

    }
}

public class synchronizedBlock extends Thread {

   boolean isRunning = true;
   boolean isRunning2 = true;
   public static Object[] locks = new Object[5];

   public synchronizedBlock() {
       for (Integer i = 0; i < 5; i++) {
           synchronizedBlock.locks[i] = i;
       }
   }

   public void cancel() {
       isRunning = false;
       interrupt();
   }

   public void socketProces() {
       while (isRunning2) {
       }
   }

   public void proces(int index) {
       try {
           synchronized (locks[index]) {
               System.out.println("Synchronized Block Begin");
               socketProces();
           }
       } catch (Exception e) {
           e.printStackTrace();
       }
   }

   @Override
   public void run() {
       try {
           System.out.println("Run begin");
           while (isRunning) {
               proces(1);
           }
           Thread.sleep(1);
       } catch (InterruptedException e) {
           //Do Something
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

结果:

Run begin
Synchronized Block Begin
Run begin
4

2 回答 2

1

这里的问题是循环中用于初始化数组的Integer缓存:forsynchronizedBlock.locks

for (Integer i = 0; i < 5; i++) {
    synchronizedBlock.locks[i] = i;
}

当此代码再次运行时,由于 second 的构造函数synchronizedBlocksynchronizedBlock.locks数组包含与第一次执行此循环时创建的相同实例。 这意味着锁将在同一个对象上。由于您已经有一个线程持有该对象的锁,因此第二个线程在等待它被释放时等待。Integerforsynchronized (locks[index]) IntegerInteger(1)lock

结合第一个线程没有终止的事实,这也是有问题的。你的方法

public void socketProces() {
    while (isRunning2) {
    }
}

是一个无限循环,因为您永远不会更改 , 的值isRunning2。此外,该interrupt() 方法本身不会停止任何线程。相反,它只在Thread类中设置一个内部标志,可以使用isInterrupted()和进行检查interrupted()。您必须检查此标志并对其做出反应,例如“哦,有人要我停下来,所以我现在停下来”。

为了解决您的问题,您至少应该在Thread设置实例的“isInterrupted”标志时退出您的线程。你可以这样做:

public void socketProces() {
    while (isRunning2) {
        if (Thread.interrupted()) {
            return;
        }
    }
}

socketProces()您可以InterruptedException像其他方法一样抛出类似的方法,而不是从正常返回。

此外,根据您要如何初始化/使用要锁定的实例synchronized(...),您可能需要考虑如何创建/填充synchronizedBlock.locks数组以及要使用哪些对象(Integer这里的缓存可能有问题)。synchronizedBlock如果创建新实例将/应该/不应该创建新对象以锁定在synchronizedBlock.locks数组中,这取决于您。

于 2021-12-23T13:07:58.833 回答
1

当你启动synchronizedBlock线程时,我认为你会得到这样的堆栈跟踪: run-> proces-> socketProcess。然后因为isRunning2 = true,线程将进入无限循环socketProcess,永不终止。

请记住,在 Java 中没有“重新启动” thread. 一旦启动,线程将永远无法重新启动。实际上,您正在创建两个sycnchronizedBlock对象,而不是重新启动单个对象。

作为旁注,在类构造函数中覆盖静态状态通常是有问题的,就像您对locks变量所做的那样,没有同步。

于 2021-12-23T08:48:47.117 回答