2016-04-05 57 views
0

我有一些反复执行相同任务的线程。在这个任务中,它必须重新验证服务以获得新的会话密钥。但是会发生什么,所有线程都会尝试重新进行验证。多线程方法

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

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

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. 
+1

你做了5个线程做同样的事情(重新认证和做的东西),你应该尝试只做一个线程认证和其他人只做东西或尝试检查线程是否已经认证,在这种情况下跳过重新认证的东西。 – aleb2000

+0

@ aleb2000有一个好处,但如果你固执己见,有各种方法可以减少对资源的访问,如 - [Semaphores](https://docs.oracle.com/javase/7/docs/api/java/ UTIL /并发/ Semaphore.html)。只要记住它会增加复杂性。 – zec

+0

我不知道信号量,是以正确的方式工作。@ zec – aleb2000

回答

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的双重检查,以调用它只有一次,没有获得任何锁,方便以后调用到reAuthenticate

+0

@HovercraftFullOfEels现在这样更好吗? –

+0

@HovercraftFullOfEels据我所知,如果答案不像预期的那样,您可以投票表决,但当答案按照要求完成时,您也应该给出答复,请不要忘记我们花时间免费帮助人们 –

+0

请允许我的时间远离我的电脑。 –

1

您可以使用​​方法来更改AtomicBooleanisAuthorized,这样可以确保线程安全的,和其他线程不会再次认证。

其次,你必须改善你的规则,你真的想如何认证,以及如何显示认证和显示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()是真实的。

+0

谢谢你,我现在在那里。我编辑了原始问题,你可以看看吗? – Mike

+0

为什么在已经是原子的块内使用AtomicBoolean?你是否打算用其他方法访问'isAuthorized'? – erickson

+0

@erickson你是对的。我用'synchronized'编辑了我的第一篇文章,并且保持其余部分不变。 – haifzhan

1

使用read-write lock.

线程可以“做的东西,”当他们获取读取锁,但必须按顺序重新进行身份验证获取写入锁定。

使用读写锁定将防止任何线程在另一个线程重新进行身份验证但不会以其他方式干扰的过程中“执行其他任务”。这将最大限度地减少由于授权而失败的请求数量,因为只要一个线程发现需要重新验证,它就会请求写入锁定,并且没有其他线程将能够获取读取锁定(因为重新认证正在等待)。

+0

我可以让其他人等待并使用与完成此操作时获得锁定的响应相同的响应吗? – Mike

+0

是的。本质上,锁会防止访问会话标识符。所有的线程都可以获得锁并读取会话标识符,但是如果发现它是无效的,则一个线程将获取写入锁,并在其更新之前排除其他线程读取它。 – erickson