Java 为什么在多个线程之间不更新该值?

Java 为什么在多个线程之间不更新该值?,java,multithreading,Java,Multithreading,下面的程序执行一个基本的多线程任务。我在一个类中有两个线程。一个线程执行增加值变量的工作,另一个线程检查值并显示消息 Class Was{ private int ctime; private int value; public Thread w,c; public was(int a) { ctime=a; w = new Thread(new Runnable() { public void run() { t

下面的程序执行一个基本的多线程任务。我在一个类中有两个线程。一个线程执行增加值变量的工作,另一个线程检查值并显示消息

Class Was{
private int ctime;
private int value;
public Thread w,c;

public was(int a) {
    ctime=a;
    w = new Thread(new Runnable() {           
        public void run() { 
            try {
                for(int i=0;i<5;i++) {
                    Thread.sleep(ctime*1000);
                    value++; 
                }
                System.out.printf("\nIncreasing done");
            } catch(InterruptedException e) { 
                System.out.println(e);
            }
    } 
    });

    c = new Thread(new Runnable() {           
        public void run() { 
            try {
                for(;;) {
                    if(value==3) {
                        w.wait();
                        System.out.printf("\nValue reached");
                        w.notify();
                        break;
                    }
                }
            } catch(InterruptedException e) { 
                System.out.println(e);
            }
        } 
    });
}
c线程从不告知已达到该值。我不明白为什么

c线程从不告知已达到该值。我不明白为什么

在线程之间共享值时,需要使用某种机制来同步保存该值的内存。这可以通过同步块完成,将值标记为volatile,或者在本例中使用AtomicInteger。这是一个例子

在这里使用AtomicInteger是正确的,因为它允许线程安全地递增。您必须记住,增量不是一个原子操作,因为它实际上是get、increment和set

您的代码看起来像:

private final AtomicInteger value = new AtomicInteger(0);
...
value.incrementAndGet();
...
if (value.get() == 3) ...
此外,正如@Boris指出的,您有以下代码:

w.wait();
System.out.printf("\nValue reached");
w.notify();

这不会编译,因为您不在同步块中。另外,先等待,然后通知是一种有点奇怪的模式。您可能还想阅读。

我对代码进行了更改,要求相同,但设计不同。所以我所理解的是线程W和C应该共享同一个监视器,当其他信号发出时,通过该监视器可以得到通知。因此,在本例中,对象锁充当监视器。我将对象锁的同一个实例传递给了线程,并调用了该锁上的wait和notify。而且效果很好。 包com.stackoverflow.gin

public class Main {

    private Object lock = new Object();
    private C c = new C(lock);
    private W w = new W(lock);

    public static void main(String[] args) {
        Main u = new Main();
        u.start();
    }

    public void start() {
        System.out.println("Start");
        c.start();
        w.start();
    }

    public class W extends Thread {
        private Object lock;

        public W(Object lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                for (;;) {
                    Thread.sleep(1000);
                    System.out.println("Notify C that I have finished work");
                    synchronized (lock) {
                        lock.notify();
                    }
                }
            } catch (Exception e) {
                System.out.println(e.getMessage() + "W");
            }
        }
    }

    public class C extends Thread {
        private int times = 0;
        private Object lock;

        public C(Object lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                for (;;) {
                    System.out.println("Waiting for W to finish ");
                    synchronized (lock) {
                        lock.wait();
                    }
                    System.out.println("W has notified " + times);
                    times++;
                    if (times == 3) {
                        System.out.println("Every thing is done, lets die to gether");
                        System.exit(0);

                    }
                }
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }

}

我认为你不能也不应该让一个线程等待另一个线程。这就像两辆车并行运行,一辆车想在另一辆车上设置断路器。这没有道理。或者这不是一个好的设计。我不知道下面是什么,你正在寻找,但看看,让我知道

import java.util.concurrent.atomic.AtomicInteger;

public class Main {

    private Object lock = new Object();
    private C c = new C(lock);
    private W w = new W(lock);
    private AtomicInteger times = new AtomicInteger();

    public static void main(String[] args) {
        Main u = new Main();
        u.start();
    }

    public void start() {
        System.out.println("Start");
        c.start();
        w.start();
    }

    public class W extends Thread {
        private Object lock;

        public W(Object lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    times.set(i + 1);
                    System.out.println("Incremented counter " + times.get());
                }
                synchronized (lock) {
                    System.out.println("Notify C that I have finished work");
                    lock.notify();
                }
            } catch (Exception e) {
                System.out.println(e.getMessage() + "W");
            }
        }
    }

    public class C extends Thread {
        private Object lock;

        public C(Object lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                for (;;) {
                    if (times.get() == 3) {
                        synchronized (lock) {
                            System.out.println("Now I will wait until W finishes with his work");
                            lock.wait();
                            System.out.println("Ok W is finished with the loop " + times.get() + " lets exit the sytem.");
                            System.exit(0);
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }

}

请遵循Java命名约定,类以大写开头。请格式化您的代码。这可能会有所帮助。在线程对象上的同步阻止之外还使用了wait和notify-我不确定int是唯一的问题。出于好奇,是什么原因导致在过去3分钟内,您编辑了5到6次答案,一直在为答案添加更多内容?我可能是我们两人之间的新手,但尽快得出答案,然后在答案中添加所有关键点,这真的很常见吗?为OP提供一点背景知识:今天几乎所有的CPU都有多核,每个核心都有自己的缓存,以加快对最近使用的变量的访问。因此,从一个线程更改变量并不一定意味着另一个线程会看到它;新值可能以独占方式存在于变异线程的缓存中,而另一个线程可能运行在不同的内核上。但是,在默认情况下使所有内容同步会对性能造成巨大影响,也会降低单线程程序的速度,因此您必须自己指定。是的@Izmaki,这是我通常回答问题的方式。如果我愿意花时间来写和编辑所有这些,那么我就永远不会有这样的想法。我回答了关键问题,其中提到了内存同步和AtomicInteger的使用,然后我返回并用指向文档和示例代码等的链接填充它。@Gray我必须说我觉得它有点俗气,但我想这就是它的工作原理,也是为什么我只在300标记处。我实际上想让线程c检查值是否达到3。如果是这样,则使线程w暂时等待并打印一条消息,然后恢复线程w以完成其将值更新为5的任务。在使变量值原子化之后,我可以在值上实现同步。但是当我使用w.wait时,我得到了非法的监视器状态异常。我需要通过实际制作w线程来完成一项任务。如果你能在你的新设计或我的设计中帮助我实现这一点,那就太好了。谢谢。。。你的设计适合我!非常感谢你的帮助。
import java.util.concurrent.atomic.AtomicInteger;

public class Main {

    private Object lock = new Object();
    private C c = new C(lock);
    private W w = new W(lock);
    private AtomicInteger times = new AtomicInteger();

    public static void main(String[] args) {
        Main u = new Main();
        u.start();
    }

    public void start() {
        System.out.println("Start");
        c.start();
        w.start();
    }

    public class W extends Thread {
        private Object lock;

        public W(Object lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(1000);
                    times.set(i + 1);
                    System.out.println("Incremented counter " + times.get());
                }
                synchronized (lock) {
                    System.out.println("Notify C that I have finished work");
                    lock.notify();
                }
            } catch (Exception e) {
                System.out.println(e.getMessage() + "W");
            }
        }
    }

    public class C extends Thread {
        private Object lock;

        public C(Object lock) {
            this.lock = lock;
        }

        @Override
        public void run() {
            try {
                for (;;) {
                    if (times.get() == 3) {
                        synchronized (lock) {
                            System.out.println("Now I will wait until W finishes with his work");
                            lock.wait();
                            System.out.println("Ok W is finished with the loop " + times.get() + " lets exit the sytem.");
                            System.exit(0);
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }

}