Java多线程修改变量未被其他线程感知问题排查求助
问题根因
- OddEven实例未共享:你在main方法的线程创建循环里,每次迭代都new了新的OddEven对象,5个线程各持有一个独立的实例,实例内部的count、threadId都是线程私有的,完全不互通。T1修改的只是自己所持实例的threadId,其他线程的实例threadId永远是初始值1,所以T2判断自己名字不等于1就会一直等待。
- threadId更新逻辑错误:你当前计算下一个threadId的逻辑是
threadId = (threadId + 1)%noOfThreads,当noOfThreads为5时,计算结果的取值范围是04,而你创建的线程名字是15,当threadId被更新为0时,没有对应名字的线程能拿到执行权,所有线程都会陷入永久等待。
修复方案
- 将OddEven实例的创建移到线程创建循环外,让所有线程共享同一个实例
- 调整threadId的更新逻辑,让取值范围匹配线程名的1~5
修复后代码示例
Main类修改
public class Main { public static void main(String args[]) { int noOfthreads = 5; Thread [] t = new Thread[noOfthreads]; // 移到循环外,所有线程共享同一个实例 OddEven oe = new OddEven(15, noOfthreads); for(int i = 0; i<noOfthreads ; i++) { t[i] = new Thread(new Runnable() { @Override public void run() { try { oe.printNumbers(); } catch (InterruptedException e) { e.printStackTrace(); }; } }); } for(int i = 0; i<noOfthreads ; i++) { t[i].setName(String.valueOf(i+1)); t[i].start(); System.out.println("started thread " + (i+1)); } for(int i=0; i<noOfthreads; i++) { try { t[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
OddEven类修改
public class OddEven { int max ; int count; Integer threadId; // 同步方法已保证可见性,可去掉volatile修饰 int noOfThreads ; public OddEven(int max, int noOfThreads) { this.max = max; this.noOfThreads = noOfThreads; count = 1 ; threadId =1; } public synchronized void printNumbers() throws InterruptedException { while(count <= max) { while(!(Thread.currentThread().getName().equals(threadId.toString()))) { wait(); } System.out.println("thread " + Thread.currentThread().getName() + " printed " + count) ; count++; // 修复更新逻辑,取值范围匹配1~noOfThreads threadId = (threadId % noOfThreads) + 1; notifyAll(); } } }
内容的提问来源于stack exchange,提问作者akrititest
相关产品推荐
相关产品推荐

