Java中带有等待和通知的死锁-线程不';当notifyAll被调用时,我不会醒来
我的程序应该使用线程(为了学习线程)按顺序打印从1到10的数字。 问题是程序陷入了死锁。为什么呢 我创建了10个这样的线程:Java中带有等待和通知的死锁-线程不';当notifyAll被调用时,我不会醒来,java,multithreading,Java,Multithreading,我的程序应该使用线程(为了学习线程)按顺序打印从1到10的数字。 问题是程序陷入了死锁。为什么呢 我创建了10个这样的线程: for (int i = 0; i < 10; i++) { new PrintThread(i).start(); } class PrintThread extends Thread { int curr; static Integer prev; PrintThread(int curr) { this.cu
for (int i = 0; i < 10; i++) {
new PrintThread(i).start();
}
class PrintThread extends Thread {
int curr;
static Integer prev;
PrintThread(int curr) {
this.curr = curr;
}
public synchronized void run() {
if (prev == null) prev = curr - 1;
while (curr != prev + 1) {
System.out.println("Waiting...");
try { wait(); }
catch (InterruptedException e){ }
System.out.println("Woke up!");
}
System.out.println(i);
prev = curr;
notifyAll();
}
}
输出
0
Waiting... (9 times)
@SotiriosDelimanolis的评论清楚地解释了这个问题。要指出解决问题的其他方法,请检查以下程序,其中一个程序使用暴力逻辑乘以时间&其他程序等待与您类似的逻辑,而不使用
wait
import java.util.Set;
public class ThreadChecker {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new PrintThread2(i+1).start();
}
}
}
//Brute force method
class PrintThread extends Thread {
int curr;
static Integer prev;
PrintThread(int curr) {
this.curr = curr;
}
public synchronized void run() {
try {
Thread.sleep(curr*100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(curr);
}
}
//Logic using Thread.sleep
class PrintThread2 extends Thread {
int curr;
static Integer prev=0;
PrintThread2(int curr) {
this.curr = curr;
}
public synchronized void run() {
while(curr!=prev && curr-prev!=1){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(curr);
prev = curr;
//Following is to debug the thread state
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for(Thread str: threadSet){
System.out.println("Thread name:"+str.getName()+
" ; State:"+str.getState().toString());
}
}
}
import java.util.Set;
公共类线程检测器{
公共静态void main(字符串[]args){
对于(int i=0;i<10;i++){
新的PrintThread2(i+1).start();
}
}
}
//蛮力法
类PrintThread扩展线程{
国际货币;
静态整数prev;
打印线程(int curr){
this.curr=curr;
}
公共同步的无效运行(){
试一试{
线程睡眠(电流*100);
}捕捉(中断异常e){
e、 printStackTrace();
}
系统输出打印项次(当前);
}
}
//使用Thread.sleep的逻辑
类PrintThread2扩展了线程{
国际货币;
静态整数prev=0;
PrintThread2(内部电流){
this.curr=curr;
}
公共同步的无效运行(){
while(curr!=prev&&curr-prev!=1){
试试{
睡眠(1000);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
系统输出打印项次(当前);
上一次=当前;
//下面是调试线程状态的步骤
Set threadSet=Thread.getAllStackTraces().keySet();
用于(线程str:threadSet){
System.out.println(“线程名称:”+str.getName()+
“状态:”+str.getState().toString());
}
}
}
所有线程都会同步并自行等待。因此,即使一个线程通知,通知也不会到达任何人,因为其他线程正在等待另一个监视对象(即它们自己)。在这种情况下,所有线程都应该在一个公共监视器对象上同步并等待/通知
您根本不应该在线程
对象上使用等待
和通知
,因为这实际上可能会导致线程调度iirc中的死锁
作为旁注:不要扩展Thread
,而是实现一个Runnable
,并提供该Runnable
的实例作为Thread
wait()、notify()和notifyAll()的构造函数的参数,这些都是对象类的方法。这应该由线程之间共享的对象调用。在这里,我编写了一个小的生产者-消费者程序,它可以消除您对wait()和notify()的疑虑
package com.mytest.example;
公共类线程演示{
int消息;
字符串threadName;
布尔消耗;
ThreadDemo(int消息、字符串threadName、布尔值){
这个.setMessage(message);
此.setThreadName(threadName);
这个.setconsumered(已消费);
}
公共静态void main(字符串[]args){
ThreadDemo=newthreaddemo(0,“Main”,true);
线程生产者=新线程(新生产者(演示));
线程消费者=新线程(新消费者(演示));
producer.start();
consumer.start();
试一试{
consumer.join();
}捕捉(中断异常e){
System.out.println(“错误:-”+e.getMessage());
}
System.out.println(“Main()退出”);
}
/**
*@回信
*/
public int getMessage(){
返回消息;
}
/**
*@param message要设置的消息
*/
公共无效设置消息(int消息){
this.message=消息;
}
/**
*@返回threadName
*/
公共字符串getThreadName(){
返回threadName;
}
/**
*@param threadName要设置的threadName
*/
public void setThreadName(字符串threadName){
this.threadName=threadName;
}
/**
*@返回可用的内容
*/
公共布尔值isConsumed(){
消费回报;
}
/**
*@param contentAvailable可设置的内容
*/
已使用公共void集合(已使用布尔值){
这个。消耗=消耗;
}
}
类生成器实现了Runnable{
线程演示;
制作人(ThreadDemo){
this.demo=demo;
}
@凌驾
公开募捐{
对于(inti=1;i而言,原因可能是因为按照线程类,除了join之外,没有其他方法可以保证在特定的时间间隔内执行。
因此,不同的线程在不同的时间间隔被调用,这是基于线程调度器的,我们不再完全控制这些方法
更确切地说,我建议观看以下视频,以了解更多关于线程的信息
希望你能在看了这三个视频后得到你的答案我尽量简短
import java.util.concurrent.atomic.AtomicInteger;
public class PrintThread implements Runnable {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new PrintThread(i)).start();
}
}
private static final AtomicInteger nextToPrint = new AtomicInteger(0);
private final int curr;
public PrintThread(int curr) {
this.curr= curr;
}
@Override
public void run() {
synchronized (nextToPrint) {
while (nextToPrint.get() != curr) {
try {
nextToPrint.wait();
} catch (InterruptedException e) { /*do nothing*/ }
}
System.out.println(curr);
nextToPrint.incrementAndGet();
nextToPrint.notifyAll();
}
}
}
导入java.util.concurrent.AtomicInteger;
公共类PrintThread实现可运行{
公共静态void main(字符串[]args){
对于(int i=0;i<10;i++){
新线程(新打印线程(i)).start();
}
}
私有静态最终AtomicInteger nextToPrint=新的AtomicInteger(0);
私人最终国际货币;
公共打印线程(int curr){
this.curr=curr;
}
@凌驾
公开募捐{
已同步(下一次打印){
while(nextToPrint.get()!=curr){
试一试{
nextToPrint.wait();
}catch(InterruptedException e){/*什么也不做*/}
}
系统输出打印项次(当前);
下托普里
import java.util.concurrent.atomic.AtomicInteger;
public class PrintThread implements Runnable {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new PrintThread(i)).start();
}
}
private static final AtomicInteger nextToPrint = new AtomicInteger(0);
private final int curr;
public PrintThread(int curr) {
this.curr= curr;
}
@Override
public void run() {
synchronized (nextToPrint) {
while (nextToPrint.get() != curr) {
try {
nextToPrint.wait();
} catch (InterruptedException e) { /*do nothing*/ }
}
System.out.println(curr);
nextToPrint.incrementAndGet();
nextToPrint.notifyAll();
}
}
}