【问题标题】:Print 1-1000 with two threads (even and odd) from the same class使用来自同一类的两个线程(偶数和奇数)打印 1-1000
【发布时间】:2025-11-23 15:05:01
【问题描述】:

所以我的任务是这样的:

  1. 实例化同一类的两个对象

  2. 提供一个构造函数参数,将一个线程指定为偶数,另一个指定为奇数。

  3. 一个接一个地启动两个线程

  4. 奇数线程打印从 0 到 1000 的奇数

  5. 偶数线程打印从 0 到 1000 的偶数

  6. 但是它们应该是同步的,打印应该是 1 , 2 , 3 , 4 .....

  7. 每行一个数字

但是我似乎无法正确释放锁。我试过在这里阅读一些类似的问题,但它们都使用多个类。我做错了什么?

编辑:我的主要班级正在这样做 -

NumberPrinter oddPrinter = new NumberPrinter("odd");
NumberPrinter evenPrinter = new NumberPrinter("even");

oddPrinter.start();
evenPrinter.start();

我的输出是 - 奇数:1 偶数:2 ...

public class NumberPrinter extends Thread {

private String name;
private int starterInt;
private boolean toggle;


public NumberPrinter(String name) {
    super.setName(name);
    this.name=name;

    if(name.equals("odd")) {
        starterInt=1;
        toggle = true;

    }
    else if(name.equals("even")) {
        starterInt=2;
        toggle = false;
    }
}

@Override
public synchronized void run() {

    int localInt = starterInt;
    boolean localToggle = toggle;

    if(name.equals("odd")) {


    while(localInt<1000) {

        while(localToggle == false)
        try {
            wait();
        }catch(InterruptedException e) {

              System.out.println("Main thread Interrupted");

        }
    System.out.println(name+": "+localInt);
    localInt +=2;
    localToggle = false;
    notify();

       }
    }

    else {

        while(localInt<1000) {


            while(localToggle == true)
                try {
                    wait();
                }catch(InterruptedException e) {

                      System.out.println("Main thread Interrupted");

                }
            System.out.println(name+": "+localInt);
            localInt +=2;
            localToggle = true;
            notify();
    }
}
}
}

【问题讨论】:

  • 使boolean localToggle 成为static AtomicBoolean 类型的字段目前它们是方法变量并且只对当前线程可见。
  • 看到这个答案*.com/a/12045001/2310289
  • 你使用了错误的synchronized,它只保证你对同一个对象的方法有多个调用时会并发,看看这个documentation
  • @Bohemian 由于 OP 正在实例化两个对象,那么 volatile boolean localToggle 是否不需要成为静态字段才能在不同线程之间共享其状态?
  • 如果您想遵守上述遇到的顺序 1 、 2 、 3 、 4 .....,那么这不是并行化的好选择。请改用顺序方法。

标签: java multithreading wait synchronized


【解决方案1】:

这里的关键问题是两个线程没有办法相互协调。当你有一个局部变量(在这种情况下为localToggle)时,方法之外的任何东西都无法观察或改变它的值。

但是,如果您与两个线程共享一个对象,则其状态可能会发生变化,如果使用正确,这些状态更改将对两个线程都可见。

您将看到共享对象为AtomicInteger 的示例,但是当您使用synchronizedwait()notify() 时,您不需要内置于原子包装器中的额外并发开销。

这是一个简单的大纲:

class Main {
  public static main(String... args) {
    Main state = new Main();
    new Thread(new Counter(state, false)).start();
    new Thread(new Counter(state, true)).start();
  }
  int counter;
  private static class Counter implements Runnable {
    private final Main state;
    private final boolean even;
    Counter(Main state, boolean even) {
      this.state = state;
      this.even = even;
    }
    @Override
    public void run() {
      synchronized(state) {
        /* Here, use wait and notify to read and update state.counter 
         * appropriately according to the "even" flag.
         */
      }
    }
  }
}

我不清楚自己使用wait()notify() 是否是作业的一部分,但此大纲的替代方法是使用BlockingQueue 之类的东西在两者之间来回传递令牌线程。 (容易出错的)状态监控将内置到队列中,清理您的代码并减少出错的可能性。

【讨论】:

    【解决方案2】:

    我终于让它以符合我的任务要求的标准的方式工作。 谢谢大家的意见。我会把答案留给可能需要的人。

    public class Demo {
    
    public static void main(String[] args) {
    
        NumberPrinter oddPrinter = new NumberPrinter("odd");
        NumberPrinter evenPrinter = new NumberPrinter("even");
    
    
    
        oddPrinter.start();
        evenPrinter.start();
    
    
    
    
        System.out.println("Calling thread Done");
    

    }

    public class NumberPrinter extends Thread {
    
    private int max = 1000;
    static Object lock = new Object();
    String name;
    int remainder;
    static int startNumber=1;
    
    
    
    public NumberPrinter(String name) {
    
            this.name = name;
    
            if(name.equals("even")) {
                remainder=0;
    
            }else {
                remainder=1;
    
    
            }
        }
    
    @Override
    public void run() {
    
    
    
            while(startNumber<max) {
                synchronized(lock) {
                    while(startNumber%2 !=remainder) {
                        try {
                        lock.wait();
                        }catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(name+": "+startNumber);
                    startNumber++;
                    lock.notifyAll();
                }
            }
    
    }
    
    }
    

    【讨论】:

      最近更新 更多