Java基础同步线程

3

我正在学习Java,但是在synchronized方面遇到了麻烦。我想从许多Java线程中打印数字列表,并使每个线程按顺序进行。当我使用synchronized时,我遇到了问题,因为我不太理解。能否帮助我理解一下?

我希望输出结果像这样,但有时线程的顺序会错乱。我想要:

1-thread1
2-thread2
3-thread1
4-thread2
5-thread1
6-thread2
...
48-thread2
49-thread1

我的破碎的代码:

public class ManyThreadsAdd {
    public static int index = 0;

    public static void main(String[] args) {
        ManyThreadsAdd myClass = new ManyThreadsAdd();
        Thread thread1 = new Thread(myClass.new RunnableClass());
        Thread thread2 = new Thread(myClass.new RunnableClass());

        thread1.start();
        thread2.start();
    }

    class RunnableClass implements Runnable {
        public synchronized void run() {
            while (index < 49) {
                try {
                    Thread.sleep(100);
                    System.out.println(index+"-" +Thread.currentThread());
                    index = index + 1;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1
你需要在这里使用wait()notify()。为了实现你想要的输出,你需要线程之间进行某种形式的通信。 - TheLostMind
是的,我尝试过使用wait和notify,但总是出现错误异常。也许有一个常见的类可以用来使用wait和notify? - JoeJoeJoeJoe4
你必须使用共享锁。请参考https://dev59.com/_lfUa4cB1Zd3GeqPFzzz中的被接受的答案。因为这是同样的问题,所以建议关闭此问题的投票。我尽力为您选择一个好的答案,但如果这无法解决您的问题,那么还有很多其他问题发布了关于此问题的答案,请在Google上搜索“java多线程奇偶数site:stackoverflow.com”。 - Nathan Hughes
你说你想使用“许多”线程,但你的示例输出显示了两个;你是使用恰好两个线程还是任意数量的线程?你是否希望线程以精确的轮询方式执行,例如t1,t2,...,tN,t1,t2,...,tN?如果你要协调任意数量的线程,解决方案会更加复杂。 - Mike Strobel
2个回答

2

这取决于您想做什么。

交替打印的简单方法是在同一个对象上进行同步,此时可以使用索引或任何其他对象。

public class ManyThreadsAdd {
    public static AtomicInteger index = new AtomicInteger(0);

    public static void main(String[] args) {
        ManyThreadsAdd myClass = new ManyThreadsAdd();
        Thread thread1 = new Thread(myClass.new RunnableClass());
        Thread thread2 = new Thread(myClass.new RunnableClass());

        thread1.start();
        thread2.start();
    }

    class RunnableClass implements Runnable {
        public void run(){
            synchronized(index){
                while(index.get() < 49){
                    try {
                      Thread.sleep(100);
                      System.out.println(index.get()+"-" +Thread.currentThread());
                      index.incrementAndGet();
                      index.notify();
                      index.wait();
                    } catch (InterruptedException e) {
                      e.printStackTrace();
                    }
                }
            }
        }
    }
}

这个我理解得最好。很容易看出原子增量,然后是notify()和wait()。谢谢。 - JoeJoeJoeJoe4

2

首先,多线程本质上是异步的,您无法指定执行这些线程的顺序。如果您想要以下输出,请使用循环:

1-thread1
2-thread2
3-thread1
4-thread2
5-thread1
6-thread2
...
48-thread2
49-thread1

其次,在 public synchronized void run() 方法中添加 synchronized 关键字对你没有任何帮助。这只意味着在任何时候,只有一个线程可以调用该方法。由于为每个线程构建新类,因此这是无意义的。
第三,在需要同步线程之间的情况下,请使用队列添加任务,并让您的线程逐一读取。

你总是打开新的RunnableClass,所以不会有同步问题。 将其变成单例类。 - Gurkan İlleez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接