【问题标题】:How to synchronize three threads of different classes together如何将不同类的三个线程同步在一起
【发布时间】:2021-05-25 18:09:30
【问题描述】:

我有三个线程,我需要将三个线程同步在一起, 我从用户那里获取 n 直到需要计数器并增加 counterOne 直到 n 值 (通过使用 ThreadOne) 并且如果 counterOne 是 25 的倍数,我需要增加值 counterTwo 乘以 2**(通过使用 hreadTwo)** 并且当 counterTwo 是 4 的倍数时,我 需要将 counterThree 增加 1 (通过使用 ThreadThree) 并且需要打印值 n = counterOne 值之后的 counterOne、counterTwo 和 counterThree。

我已经实现了这个,这是代码,但是 counterTwo 和 counterOne 的值没有增加。 我做错了什么?

测试用例

输入:30

输出 : counterOne: 30, counterTwo: 0 counterThree:0

CounterOne 将一一增加,当遇到 25 倍数时 counterTwo 应增加二,当添加 4 倍数时 counterThree 应增加一。

但是当在 counterOne 中添加 25 时,它应该将 counterTwo 增加 2,但它没有增加 counterOne 到 30 4 ,8,12,16,20,24,28 这些都是 4 的倍数,所以counterThree 应该是 7,但它也是 0。

输出应该是:counterOne: 30, counterTwo: 1 counterThree:7

代码如下:

计数器类

  public class Counter {
        int counterOne;
        int counterTwo;
        int counterThree;
        int flag = 0;
    }

主类

 import java.util.Scanner;
        class Main {
        public static void main(String args[]) {
            Scanner in = new Scanner(System.in);
            int n = in.nextInt();
    
            Counter count = new Counter();

        ThreadOne objOne = new ThreadOne(count, n);
        Thread one = new Thread(objOne);

        ThreadTwo objTwo = new ThreadTwo(count);
        Thread two = new Thread(objTwo);

        ThreadThree objThree = new ThreadThree(count);
        Thread three = new Thread(objThree);

        try {
            one.start();
            two.start();
            three.start();

        } catch (Exception e) {
            e.printStackTrace();
        }
        in.close();
    }
}

ThreadOne 类

 class ThreadOne implements Runnable {
        Counter count;
        int n;
    
        public ThreadOne(Counter count, int n) {
            this.count = count;
            this.n = n;
        }
         @Override
        public synchronized void run() {
               while (count.counterOne != n) {
                     count.counterOne += 1;
                   }
                  if (count.counterOne == n) {
                count.flag = 1;
                System.out.print(count.counterOne + " " + count.counterTwo + " " + count.counterThree);
            }
         }
      }

ThreadTwo 类

class ThreadTwo implements Runnable {
    Counter count;
    public ThreadTwo(Counter count) {
        this.count = count;
    }
    @Override
    public synchronized void run() {
        while (count.flag != 1) {
            if (count.counterOne % 25 == 0) {
                count.counterTwo += 2;
            }
        }
    }
}

ThreadThree 类

class ThreadThree implements Runnable {
    Counter count;
    public ThreadThree(Counter count) {
        this.count = count;
    }
    @Override
    public synchronized void run() {
        while (count.flag != 1) {
            if (count.counterTwo % 4 == 0) {
                count.counterThree += 1;
            }
        }
    }

}

【问题讨论】:

  • 您可能想查看可见性保证、volatile 和原子引用。
  • 我不清楚这些解释。我认为您需要向我们展示minimal reproducible example 以向我们展示实际问题,如果不是,请在文本中添加进一步的解释。
  • @markspace 添加示例

标签: java multithreading synchronization


【解决方案1】:

这里有几个问题:

数字 1 是 synchronized 仅在线程运行相同的代码块时才有效。因此,当您在每个线程中有一个单独的同步块时,它们不会相互锁定。您可以设置要锁定的对象,只要所有块都引用同一个对象作为锁定,这将起作用。

数字 2 是线程 1 可能在其他 2 个线程甚至开始之前完成。所以他们没有机会建立锁。这就是你得到全零的原因。

第三个问题是你的循环做的太少了,以至于它们重复多次而没有松开锁。所以你真的需要一个sleep(),这样它才能更好地工作。

数字 4 是您假设每个线程将一次整齐地排队排队。你不能这样假设。实际上,一些线程可能会在任何其他特定线程进入之前运行多次。如果发生这种情况,它会打乱你的计数。

第 5 个问题是您的代码中有几个简单的错误会导致它无法工作。例如,线程 3 将线程 2 计数器除以 4,而不是线程 1 计数器。所以 CounterThree 永远不可能是 N 小于 50 的非零。

但第 4 点是要解决的最大问题。您不能线性思考,因此您必须假设每个线程中循环的每次执行在其逻辑上都是完全独立的。换句话说,您不能假设其他两个线程在每次循环执行之间都只运行一次。所写的代码显然有这个假设,当我让它运行所有线程时,它给出了完全疯狂的数字。

我在Counter 中引入了两个新字段。 lastCheckedByTwo 和 lastCheckedByThree。我还将整数标志字段更改为布尔值,并将其命名为更有意义的名称continueCounting。不要将整数用作布尔值。

现在循环发生了变化,ThreadOne 仅在 ThreadTwo 和 ThreadThree 都完成模逻辑时增加 counterOne。后两个线程在完成工作后更新lastCheckedByTwo 和lastCheckedByThree。每增加一次counterOne,他们只做一次他们的工作。

基本上这意味着Counter 现在拥有进程的完整状态,并且各个线程在工作时对其进行更新,并检查它以确保它们应该做任何事情。

我将同步块作为 Main 的静态方法移动,它接受来自调用方法的可运行对象,这些调用方法位于各种线程类中。为了更容易查看调用了哪些线程以及调用了多少次,我给出了线程名称并在方法中调用了System.out.println()。

您可以在updateCounter() 方法中弄乱sleep()。如果您将其设置得非常低,您会看到整个系统将开始颠簸,并且需要很长时间才能完成来自同一线程的成千上万的背靠背调用。 30 毫秒似乎是一个不错的时间。

class Main {
    static Counter count = new Counter();
    static int loopCounter = 0;

    public static void main(String args[]) {
        System.out.println("How Much? ");
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();

        try {
            new Thread(new ThreadOne(count, n), "Thread 1").start();
            new Thread(new ThreadTwo(count), "Thread 2").start();
            new Thread(new ThreadThree(count), "Thread 3").start();
        } catch (Exception e) {
            e.printStackTrace();
        }
        in.close();
    }

    public synchronized static void updateCounter(Runnable updater) {
        updater.run();
        try {
            Thread.sleep(30);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(++loopCounter + "   " + Thread.currentThread()
                                                         .getName() + " -> One: " + count.counterOne + " Two: " + count.counterTwo + " " + "Three:" + " " + count.counterThree);
    }
}


class ThreadOne implements Runnable {
    Counter count;
    int n;

    public ThreadOne(Counter count, int n) {
        this.count = count;
        this.n = n;
    }

    @Override
    public void run() {
        while (count.continueCounting) {
            Main.updateCounter(() -> {
                if ((count.lastCheckedByTwo == count.counterOne) && (count.lastCheckedByThree == count.counterOne)) {
                    count.counterOne += 1;
                    if (count.counterOne == n) {
                        count.continueCounting = false;
                        System.out.println(count.counterOne + " " + count.counterTwo + " " + count.counterThree);
                    }
                }
            });
        }
    }
}


class ThreadTwo implements Runnable {
    Counter count;

    public ThreadTwo(Counter count) {
        this.count = count;
    }

    @Override
    public void run() {
        while (count.continueCounting) {
            Main.updateCounter(() -> {
                if (count.lastCheckedByTwo != count.counterOne) {
                    count.lastCheckedByTwo = count.counterOne;
                    if (count.counterOne % 25 == 0) {
                        count.counterTwo += 2;
                    }
                }
            });
        }
    }
}


class ThreadThree implements Runnable {
    Counter count;

    public ThreadThree(Counter count) {
        this.count = count;
    }

    @Override
    public synchronized void run() {
        while (count.continueCounting) {
            Main.updateCounter(() -> {
                if (count.lastCheckedByThree != count.counterOne) {
                    count.lastCheckedByThree = count.counterOne;
                    if (count.counterOne % 4 == 0) {
                        count.counterThree += 1;
                    }
                }
            });
        }
    }
}


public class Counter {
    int counterOne = 0;
    int counterTwo = 0;
    int counterThree = 0;
    int lastCheckedByTwo = 0;
    int lastCheckedByThree = 0;
    boolean continueCounting = true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多