java - 一个线程改变的变量不会被其他线程看到
问题描述
我创建了 5 个线程T1,T2..T5
。T1
设置threadId
并计数为2
。
随后,T2
应该继续,因为循环while(!(Thread.currentThread().getName().equals(threadId.toString())))
应该失败。
但是对于T2
,threadId
仍然存在1
,因此它也在等待。
请让我知道我在这里缺少什么。
public class Main {
public static void main(String args[])
{
int noOfthreads = 5;
Thread [] t = new Thread[noOfthreads];
for(int i = 0; i<noOfthreads ; i++) {
OddEven oe = new OddEven(15, noOfthreads);
t[i] = new Thread(new Runnable() {
@Override
public void run() {
try {
oe.printNumbers();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class OddEven {
int max ;
int count;
volatile Integer threadId;
int noOfThreads ;
public OddEven(int max, int noOfThreads) {
super();
this.max = max;
this.noOfThreads = noOfThreads;
count = 1 ;
threadId =1;
}
//TODO: Try to pass threadId as a parameeter here
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++;
threadId = (threadId + 1)%noOfThreads;
notifyAll();
}
}
}
解决方案
彼此看不到更改,因为线程之间没有共享状态。每个线程都有自己的OddEven
实例,因此只有 T1 继续跳过对 wait() 的调用(其 threadId 已经为 1)并终止。T2(和其余的)永远不会超过 wait() 调用,因为没有人会更改其OddEven
实例的 threadId 字段。
您可以做的第一件事是将 OddEven 的实例化移到创建线程的 for 循环之外:这样每个线程都将使用相同的OddEven
实例。
当你这样做时,你会注意到前 4 个线程将通过第一次调用 wait() (然后它们将卡在第二次 wait() 调用),而 thread5 将继续卡在第一次 wait( ) 调用:这是因为 threadId 永远不会达到 5,它会走 [0..4] 范围(因为你有 threadId % 5)。要解决此问题,只需从 0 开始命名您的线程,或修复模运算。
当你这样做时,程序实际上将终止。但是您会注意到您将打印 5 次以上(线程数)超过最大值。这是因为 count <= max 条件在线程执行增量“之前”被检查。我不知道您想要实现/观察什么,因此我无法就此提供更多建议。
我上面解释的代码,所以你可以自己试试:
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));
t[i].start();
System.out.println("started thread " + (i));
}
for(int i=0; i<noOfthreads; i++) {
try {
t[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class OddEven {
int max ;
int count;
volatile Integer threadId;
int noOfThreads ;
public OddEven(int max, int noOfThreads) {
super();
this.max = max;
this.noOfThreads = noOfThreads;
count = 1 ;
threadId = 0;
}
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++;
threadId = (threadId + 1)%noOfThreads;
System.out.println("thread " + Thread.currentThread().getName() + " nextThreadId " + threadId) ;
notifyAll();
}
}
}
}
推荐阅读
- postgresql - 带有子查询的 SQL 条件返回操作数错误
- swift - 在 SwiftUI 上的 Firebase 中使用 updateData 函数时出错
- git - 有没有办法让 git add --patch 跳过所有单行更改?
- android - Android 应用程序与 Play 商店中的新设备不兼容
- android - UI Automator - 获取 XY 坐标的背景颜色
- javascript - 检查输入值是否为回文的函数总是返回 true
- c# - 从 Git 存储库签出后编译测试套件时 MsBuild 失败
- node.js - 如何在没有 node.js 的情况下运行 Angular 应用程序
- apache-spark - 如何使用 Spark RDD 高效实现 Simrank?
- parsing - ANTLR4 解析器问题