繁体   English   中英

Java线程同步-以正确的顺序打印数字

[英]Java Thread synchronization - printing out numbers in right order

我正在学习如何在Java中使用线程,我需要一些建议。

我想在0..50的标准输出数字上打印使用三个线程完成的线程的名称。

我有两个类-实现Runnable的Counter 和创建并运行线程的Main类 计数器具有在线程之间共享的变量c

我的想法是,我将c加1,然后在当前线程上调用yield() ,以便其他线程也可以这样做。 重复此操作,直到c达到50。

但这不起作用,数字打印顺序错误。 我该如何解决?

public class Counter implements Runnable {

Thread t1;
private int c = -1;

public Counter() {
}

public Counter(String name) {
    t1 = new Thread(this, name);
    t1.start();
}

@Override
public void run() {
    while (c < 50) {
        increment();
        Thread.yield();
    }
}

public void increment() {
    if (c < 50) {
        c++;
        System.out.println(Thread.currentThread().getName() + ": " + c);
    }
}
}

public class Main {

public static void main(String[] args) throws IllegalThreadStateException {
    Counter c1 = new Counter();
    Thread t1 = new Thread(c1, "Thread 1");
    Thread t2 = new Thread(c1, "Thread 2");
    Thread t3 = new Thread(c1, "Thread 3");

    t1.start();
    t2.start();
    t3.start();

}

编辑:最终我以这种方式解决了它。 谢谢所有帮助我艰难地开始多线程工作的人。

import java.util.concurrent.atomic.AtomicInteger;

public class Counter2 implements Runnable {

// you could also use simple int
private AtomicInteger c = new AtomicInteger(-1);
private static final Object syncObject = new Object();

public Counter2() {
}

@Override
public void run() {
    while (c.get() < 50) {
        synchronized (syncObject) {
            if (c.get() < 50) {
                System.out.println(Thread.currentThread().getName() + ": " + c.incrementAndGet());
            }
        }
    }
}    
}

在带有特殊静态对象的方法增量中使用同步部分。

private static final Object syncObj = new Object();

public void increment()
{
  syncrhonized( syncObj )
  {
   c++;
   System.out.println(c);
  }
}

或通过其声明使此方法同步。

但是将实际数据存储在线程对象中是错误的想法。 线程应该只使用共享对象进行操作,而不要存储它们。\\实际上我不明白为什么要在其中启动线程

使increment()同步,以防止其他线程同时进入方法。

yield()结合使用,您应该能够使另一个线程打印下一个数字(并非总是如此,因为系统可能会再次恢复调用yield的线程-请参阅Ingo的答案-,但顺序应相同)。

synchronized increment()意味着,如果另一个线程通过输入方法已经获取了锁,则试图在同一对象上输入该方法的任何线程都必须等待。

引用javadoc Thread.yield(),我强调:

public static void yield()

给调度程序的提示是当前线程愿意放弃当前使用的处理器。 调度程序可以随意忽略此提示

...

很少适合使用此方法。

是的,您的代码无效。 Thread#yield()不会以您期望的方式控制线程调度程序。 我很好奇您会得到什么结果。您可能会得到重复的数字,有些数字会有些混乱。

您可以使用原子整数,该整数应删除所有重复项。 但是由于print语句不是原子的。 您仍然可以不按顺序打印结果。 因此,您可能应该仅同步增量方法。 另外,您实际上并不需要产量,所以将其丢弃。

如果问题的目的是从线程1到线程2再到线程3再回到线程1,依此类推,那么结果是

Thread 1:0
Thread 2:1
Thread 3:2
Thread 1:3
Thread 2:4
Thread 3:5
Thread 1:6
Thread 2:7
....

然后,您需要锁定增量方法,并使用wait和notifyAll。 等待将导致其他线程停止处理,直到当前线程通知它们再次启动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM