可以使用静态变量来同步线程吗?

时间:2018-12-11 05:14:47

标签: java multithreading static-variables thread-synchronization

下面,我构建了一个示例,该示例基于静态变量同步三个线程:

public class CallMethodsInOrder {

    public static void main(String[] args) {
        // Three instances of Thread, first calls first, second second and third third.
        // Ensure that they are all called in order.

        Thread first = new Thread(new FooRunner(new Foo(),MethodToCall.FIRST));
        Thread second = new Thread(new FooRunner(new Foo(),MethodToCall.SECOND));
        Thread third = new Thread(new FooRunner(new Foo(),MethodToCall.THIRD));

        third.start();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        second.start();
        first.start();
    }
}

class Foo {
    static boolean hasFirstRun = false;
    static boolean hasSecondRun = false;
    static boolean hasThirdRun = false;

    public Foo() {
    }

    public void first() {
        System.out.println("First");
        hasFirstRun = true;
    }

    public void second() {
        System.out.println("Second");
        hasSecondRun = true;
    }

    public void third() {
        System.out.println("Third");
        hasThirdRun = true;
    }
}

class FooRunner implements Runnable{

    private Foo foo;
    private MethodToCall method;

    public FooRunner(Foo foo, MethodToCall method) {
        this.foo = foo;
        this.method = method;
    }

    @Override
    public void run() {
        if(method == MethodToCall.FIRST) {
            foo.first();
        }
        else if (method == MethodToCall.SECOND){
            while(!Foo.hasFirstRun) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            foo.second();
        }
        else if (method == MethodToCall.THIRD) {
            while(!Foo.hasSecondRun) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            foo.third();
        }
    }
}

enum MethodToCall{
    FIRST, SECOND, THIRD;
}

这是有效的方法吗?我已经读过静态变量不是线程安全的,但是,看不到上述代码无法按所需顺序(第一,第二,第三)执行这三种方法的情况。

我发现许多答案都与访问具有多个线程的数据结构以及此处显示的方法顺序有关。

由于每个静态变量仅由单个线程修改,这有问题吗?

2 个答案:

答案 0 :(得分:1)

如评论中所建议,使用同步可能是此处的解决方法。我觉得上面的代码仍然可以使用静态变量,但是绝对不是最好的做法。

以下包括信号量的相关解决方案:

public class CallMethodsInOrder2 {

    public static void main(String[] args) {
        // Three instances of Thread, first calls first, second second and third third.
        // Ensure that they are all called in order.

        // This approach uses Semaphore vs static variables.

        Foo2 foo2 = new Foo2();

        Thread first = new Thread(new FooRunner2(foo2,MethodToCall.FIRST));
        Thread second = new Thread(new FooRunner2(foo2,MethodToCall.SECOND));
        Thread third = new Thread(new FooRunner2(foo2,MethodToCall.THIRD));

        third.start();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        second.start();
        first.start();
    }

}

class Foo2 {
    private Semaphore one, two;

    public Foo2() {
        one = new Semaphore(1);
        two = new Semaphore(1);

        try {
            one.acquire();
            two.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void first() {
        System.out.println("First");
        one.release();
    }

    public void second() {
        try {
            one.acquire();
            System.out.println("Second");
            one.release();
            two.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void third() {
        try {
            two.acquire();
            two.release();
            System.out.println("Third");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

答案 1 :(得分:0)

在这种情况下,我认为静态变量方法“有效”(对于“有效”的某些值),但是效率肯定较低。

您在每个线程('100')中睡了任意时间,然后醒来轮询此变量。对于信号量,操作系统负责线程的睡眠/唤醒事件。