多线程方法

时间:2016-04-05 19:39:51

标签: java multithreading

我有一些运行的线程一遍又一遍地执行相同的任务。在该任务中,它必须使用服务重新进行身份验证以获取新的会话密钥。但是会发生的是所有线程都试图重新进行身份验证。

我想这样做,以便第一个线程重新验证通过,其他人等待完成,然后像往常一样继续。

这是我在实施解决方案之前的原始测试代码:

public class Main {

    public static void main(String args[]){
        new Main();
    }

    public Main(){
        AuthManager authClass = new AuthManager();

        for (int i = 0; i < 5; i++) {
            Thread thr = new Thread(() -> {
                int count = 0;

                while(count < 2) { // Bad practice but just for the example.
                    if(count == 1){
                        if(authClass.reAuthenticate()) {
                            System.out.println("Reauthenticated.");

                            authClass.doStuff();
                        }
                    } else {
                        authClass.doStuff();
                    }

                    count++;
                }
            });

            thr.start();
        }

        // Keep the program running for 30 seconds.
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            // ignored
        }
    }

    private class AuthManager {

        public boolean reAuthenticate(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // ignored
            }

            System.out.println("Reauthenticating..");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // ignored
            }

            return true; // or false when no success in the real application.
        }

        public void doStuff(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // ignored
            }

            System.out.println("Doing stuff.");
        }

    }
}

响应:

Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Reauthenticating..
Reauthenticating..
Reauthenticating..
Reauthenticating..
Reauthenticating..
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.

我想要的回应:

Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Reauthenticating..
Reauthenticated.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.

我怎样才能做到这一点?

修改 我现在用@haifzhan的回复做了这个,但是当我不得不再次进行身份验证时,这将不起作用。

public class Main {

    public static void main(String args[]){
        new Main();
    }

    public Main(){
        AuthManager authClass = new AuthManager();

        for (int i = 0; i < 5; i++) {
            Thread thr = new Thread(() -> {
                int count = 0;

                while(count < 4) { // Bad practice but just for the example.
                    if(count == 1 || count == 3){
                        if(authClass.reAuthenticate()) {
                            System.out.println("Reauthenticated.");

                            authClass.doStuff();
                        }
                    } else {
                        authClass.doStuff();
                    }

                    count++;
                }
            });

            thr.start();
        }

        // Keep the program running for 30 seconds.
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            // ignored
        }
    }

    private class AuthManager {

        private final AtomicBoolean isAuthorized = new AtomicBoolean();

        public synchronized boolean reAuthenticate() {
            if(!isAuthorized.get()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // ignored
                }

                System.out.println("Reauthenticating..");

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // ignored
                }

                isAuthorized.set(true);
                return isAuthorized.get();
            }

            return isAuthorized.get();
        }

        public void doStuff(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // ignored
            }

            System.out.println("Doing stuff.");
        }

    }
}

响应:

Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Reauthenticating..
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Reauthenticated.
Doing stuff.
Reauthenticated.
Doing stuff.
Reauthenticated.
Doing stuff.
Reauthenticated.
Doing stuff.
Reauthenticated.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.

我想要的回应:

Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Reauthenticating..
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Reauthenticating..
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Reauthenticated.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.
Doing stuff.

3 个答案:

答案 0 :(得分:2)

这是一个潜在的解决方案:

            Thread thr = new Thread(() -> {
                int count = 0;

                while(count < 2) { // Bad practice but just for the example.
                    if (count == 1 && authClass.reAuthenticate()) {
                        System.out.println("Reauthenticated.");

                        authClass.doStuff();
                    } else {
                        authClass.doStuff();
                    }

                    count++;
                }
            });

在第一个代码段中,我修改了一些逻辑,以便在auth.doStuff()返回reAuthenticate的情况下调用false

    private class AuthManager {

        private volatile boolean reAuthenticate;
        public boolean reAuthenticate(){
            if (!reAuthenticate) {
                synchronized (this) {
                    if (!reAuthenticate) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // ignored
                        }

                        System.out.println("Reauthenticating..");

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // ignored
                        }
                        return this.reAuthenticate = true;
                    }
                }
            }
            return false;
        }

在第二个代码片段中,我依靠一个volatile变量来对值reAuthenticate进行双重检查,以便只调用一次,而不必获取任何锁以便以后调用{ {1}}。

答案 1 :(得分:1)

您可以使用synchronized方法更改AtomicBoolean isAuthorized,这样可以确保线程安全,而其他线程也不会重新进行身份验证。

其次,您必须改进规则,确定您真正想要进行身份验证的方式,以及如何显示经过身份验证并显示doStuff。在你的while循环中,无论条件或条件是否满足,都打印doStuff,你需要找到区分结果的方法。

public synchronized boolean reAuthenticate(){
    if(! isAuthorized.get()){
        System.out.println("Reauthenticating..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // ignored
        }
        isAuthorized.set(true);
        return isAuthorized.get();
    }

    return isAuthorized.get(); // or false when no success in the real application.
}

输出:

 else doStuff
    else doStuff
    else doStuff
    else doStuff
    else doStuff
    Doing stuff
    Reauthenticating..
    Doing stuff
    Doing stuff
    Doing stuff
    Doing stuff
    Reauthenticated.
    Reauthenticated.
    Reauthenticated.
    Reauthenticated.
    Reauthenticated.
    Doing stuff
    Doing stuff
    Doing stuff
    Doing stuff
    Doing stuff

Reauthenticated多次打印,因为您的代码在reAuthenticate()为真后打印此行。

答案 2 :(得分:1)

使用read-write lock.

线程可以&#34;做东西,&#34;当他们获得读锁定,但必须获取写锁定才能重新进行身份验证。

使用读写锁将阻止任何线程执行操作&#34;在另一个线程重新进行身份验证的时候,但是否则会干扰。这将最大限度地减少因授权而失败的请求数,因为一旦一个线程注意到需要重新认证,它就会请求写锁定,而其他线程都无法获取读锁定(并且因为失败,因为重新认证正在等待。)