首页 > 解决方案 > 一个线程改变的变量不会被其他线程看到

问题描述

我创建了 5 个线程T1,T2..T5T1设置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();
       }
}

}

标签: javamultithreading

解决方案


彼此看不到更改,因为线程之间没有共享状态。每个线程都有自己的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();
        }
    }
}

}


推荐阅读