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

Java线程同步-按正确顺序打印数字,java,multithreading,synchronization,Java,Multithreading,Synchronization,我正在学习如何使用Java中的线程,我需要一些建议 我想在0..50的标准输出数字上打印使用三个线程完成的线程的名称 我有两个类——实现Runnable的类计数器和创建并运行线程的类Main。计数器具有在线程之间共享的变量c 我的想法是,我将c增加1,然后在当前线程上调用yield(),其他线程也会这样做。重复此操作,直到c达到50 但是它不起作用,数字是按错误的顺序打印出来的。我该如何解决这个问题 public class Counter implements Runnable { Thre

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

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

我有两个类——实现Runnable的类计数器和创建并运行线程的类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();

}
公共类计数器实现可运行{
螺纹t1;
私有int c=-1;
公众柜位(){
}
公共计数器(字符串名称){
t1=新线程(此,名称);
t1.start();
}
@凌驾
公开募捐{
而(c<50){
增量();
螺纹屈服强度();
}
}
公共空间增量(){
如果(c<50){
C++;
System.out.println(Thread.currentThread().getName()+“:”+c);
}
}
}
公共班机{
公共静态void main(字符串[]args)引发IllegalThreadStateException{
计数器c1=新计数器();
螺纹t1=新螺纹(c1,“螺纹1”);
螺纹t2=新螺纹(c1,“螺纹2”);
螺纹t3=新螺纹(c1,“螺纹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());
            }
        }
    }
}    
}
导入java.util.concurrent.AtomicInteger;
公共类计数器2实现可运行{
//也可以使用简单int
私有原子整数c=新的原子整数(-1);
私有静态最终对象syncObject=新对象();
公众谘询委员会2(){
}
@凌驾
公开募捐{
while(c.get()<50){
已同步(同步对象){
如果(c.get()<50){
System.out.println(Thread.currentThread().getName()+”:“+c.incrementAndGet());
}
}
}
}    
}
使
increment()
同步,以防止其他线程同时进入该方法

yield()
配合使用,您应该能够让另一个线程打印下一个数字(不总是这样,因为系统可能会再次恢复调用
yield
的线程-请参见Ingo的答案-,但顺序应该仍然相同)


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

使用带有特殊静态对象的方法增量中的syncrhonized部分

private static final Object syncObj = new Object();

public void increment()
{
  syncrhonized( syncObj )
  {
   c++;
   System.out.println(c);
  }
}
或者通过其声明使此方法同步

但将真实数据存储在线程对象中的想法是错误的。线程应该只处理共享对象,而不存储它们\
事实上,我不明白为什么要引用javadoc thread.yield()中的thread,我强调:

public static void yield()
向调度程序提示 当前线程愿意放弃它的 处理器的当前使用情况。 调度器可以随意忽略这一点 提示

很少适合使用它 这个方法


是的,您的代码无法工作。Thread#yield()无法按您希望的方式控制线程调度程序。我很好奇您得到了什么结果。您可能会得到重复的数字和一些稍微不符合顺序的数字

您可以使用原子整数,它应该删除所有重复项。但是由于print语句不是原子的。您可能仍然会按顺序打印结果。因此,您可能只需要同步increment方法。此外,您实际上不需要yield,所以请转储它

如果问题的目的是从线程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。wait将导致其他线程停止处理,直到当前线程通知它们重新开始。

您可以发布一些示例,说明它们现在打印的顺序吗?您希望得到什么输出,得到什么输出?AtomicInteger由线程完成1仅读取1:0
线程2:1
线程3:2。。。。