繁体   English   中英

如何将不同类的三个线程同步到一起

[英]How to synchronize three threads of different classes together

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

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

测试用例

输入:30

output :counterOne:30,counterTwo:0 counterThree:0

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

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

output 应该是:counterOne:30,counterTwo:1 counterThree:7

下面的代码:

计数器 class

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

主class

 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

 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);
            }
         }
      }

螺纹双class

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;
            }
        }
    }
}

螺纹三class

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;
            }
        }
    }

}

这里有几个问题:

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

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

第三个是你的循环做的很少,以至于它们重复多次而没有让 go 锁定。 所以你真的需要一个sleep()在那里它会更好地工作。

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

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

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

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

现在循环发生了变化,因此ThreadOne仅在ThreadTwoThreadThree都完成了它们的模逻辑时才增加counterOne 后两个线程在完成他们的工作后更新lastCheckedByTwolastCheckedByThree 而且他们只为counterOne的每个增量做一次他们的事情。

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

我将同步块移动为 Main 的 static 方法,它接受来自调用方法的可运行对象,这些调用方法位于各种线程类中。 为了更容易查看调用了哪些线程以及调用了多少次,我给了线程名称并在方法中放置了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;
}

暂无
暂无

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

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