简化同步

时间:2019-03-18 10:45:52

标签: java

我目前正在研究线程和同步。 我正在尝试使用此程序将“ A”打印两次,“ B”打印一次和“ C”打印四次,这基本上是可行的,但我想知道是否有更小,更简单的解决方案,例如将所有分为一个或类似的东西。

这是代码。

public class foo {

public static int countA = 0;
public static int countB = 0;
public static int countC = 0;


public static void main(String[] args) {


    AThread athread = new AThread(new AClass());
    BThread bthread = new BThread(new BClass());
    CThread cthread = new CThread(new CClass());

    athread.start();
    bthread.start();
    cthread.start();


}

static class AClass {

    public synchronized void printA() throws InterruptedException {
        if(countA == 2)
            wait();
        for(int i=1; i<3; i++) {
            System.out.println("A"+i);
            countA++;
        }
    }

}

static class BClass{
    public synchronized void printB() throws InterruptedException {
        if(countB == 1)
            wait();
        for(int i=1; i<2; i++) {
            System.out.println("B"+i);
            countB++;
        }
    }
}

static class CClass{ 
    public synchronized void printC() throws InterruptedException {
        if(countC == 4)
            wait();
        for(int i=1; i<5; i++) {
            System.out.println("C"+i);
            countC++;
        }
    }
}

static class AThread extends Thread {

    AClass A = new AClass();

    AThread(AClass a){
        this.A = a;
    }
    public void run() {
        try {
            A.printA();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
static class BThread extends Thread {

        BClass B = new BClass();

        BThread(BClass b){
            this.B = b;
        }
        public void run() {
            try {
                B.printB();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
static class CThread extends Thread {

    CClass C = new CClass();

    CThread(CClass c){
        this.C = c;
    }
    public void run() {
        try {
            C.printC();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

}

2 个答案:

答案 0 :(得分:1)

即使该任务不需要线程,这也是使用Java 8 CompletableFuture

在描述中编写代码的另一种方式
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        for (int i = 0; i < 2; i++) {
            System.out.println("A" + (i + 1));
        }
    }).thenRunAsync(() -> {
        System.out.println("B1");
    }).thenRunAsync(() -> {
        for (int i = 0; i < 5; i++) {
            System.out.println("C" + (i + 1));
        }
    });

答案 1 :(得分:0)

正如第一条评论所述,您的任何对象之间都没有任何同步。也许可以通过更改启动线程的顺序(首先是C,然后是B,然后是A)来改变这种情况。

要在线程之间进行调度以工作,您需要:

  • 找到一个对两个线程都可见的对象,以便两个线程都可以对该对象进行wait()和notify()。
  • 确定将导致等待停止的条件,并将其放入while()

所以您会得到:

while (countA < 2) AClass.class.wait();

在B线程中 (并在循环中捕获InterruptedException,请勿传播)

并在您放置的A线程中

AClass.class.notify();

退出打印循环后。

您可以(并且在大多数情况下应使用工业设置)将AClass.class替换为专用于此目的的同步对象(并且这两个线程都可以看到该对象)。

while()是必需的,因为所谓的“虚假唤醒”:wait()将在notify()导致它退出的情况下退出,但也可以在没有notify()导致的情况下退出已发布。

最后,请注意,while()循环中的条件从线程B访问countA字段,而线程A可能正在更新它。对于简单的整数,这仍然可能是防故障的,但是对于更复杂的评估,这本身就是争用条件错误的潜在来源,因此,这些访问需要依次同步。另请注意,如果线程A由于任何原因而崩溃,while(countA<2)可能永远不会成真,因此这是 不是 的最可靠的设置方法,因为它将导致系统崩溃。挂起。

如果所有这些都比英语更像乱语,则应首先尝试找到一个不错的线程教程,并仔细研究。