Lamport麪包店算法是解決多個線程併發訪問一個共享的單用戶資源的互斥問題的算法。由萊斯利·蘭波特發明。git
Lamport把這個併發控制算法很是直觀地類比爲顧客去麪包店採購。github
這個類比中的顧客就至關於線程,而入店購貨就是進入臨界區獨佔訪問該共享資源。因爲計算機實現的特色,存在兩個線程得到相同的簽到號碼的狀況,這是由於兩個線程幾乎同時申請排隊的簽到號碼,讀取已經發出去的簽到號碼狀況,這兩個線程讀到的數據是徹底同樣的,而後各自在讀到的數據上找到最大值,再加1做爲本身的排隊簽到號碼。算法
爲此,該算法規定若是兩個線程的排隊簽到號碼相等,則線程id號較小的具備優先權。併發
Lamport時間戳原理以下:分佈式
當知足如下兩個條件時,進程A會被分配該資源:ui
private void processRevcMsg(Message m) throws InterruptedException { // 原理4 若是事件屬於接收事件,時間戳 = Max(本地時間戳,消息中的時間戳) + 1 clock.update(m.getTimestamp()); lastSendMap.put(m.getFrom(), m); switch (m.getMsgType()) { case REQUEST_RES: // rule 2 當進程B接收到了進程A的(Tm:A)請求後,會把它放到本身的請求隊列,而後發送一個帶時間戳的確認消息給A addMessageToReqMap(m); Message ackMsg = new Message(pid, m.getMsgId(), MessageType.REQUEST_ACK, clock.time()); // send ack to sender sendToTargetProcess(ackMsg,m.getFrom()); break; case REQUEST_ACK: break; case RELEASE_RES: // rule 4 當進程B接收到進程A釋放資源的請求,它會移除隊列中任意的(Tm:A)的資源請求 dropMessageFromReqMap(m); break; default: break; } tryToAcquireResource(); } private void tryToAcquireResource() { synchronized (reqMap) { if(!reqMap.containsKey(pid) || reqMap.get(pid).isEmpty()){ return ; } Message myMessage = reqMap.get(pid).get(0); int acceptCount = 1; // rule 5 當知足如下兩個條件時,進程A會被分配該資源:a)有一個(Tm:A)的請求,按照=>關係排在隊列第一位;b)A接收到了一個時間戳大於Tm的來自全部其餘進程的消息 // condition (ii) of rule 5 // A接收到了一個來自全部其餘進程的消息,並且時間戳大於Tm for (Map.Entry<Integer, Message> entry : lastSendMap.entrySet()) { if (entry.getKey() == pid) { continue; } if (isFirstEarlier(myMessage, entry.getValue())) { acceptCount++; }else{ return ; } } if (!coordinator.hasAcceptedAll(acceptCount)){ return; } // condition (i) of rule 5 // 有一個Tm:A的請求,按照=>關係排在隊列第一位 for (Map.Entry<Integer, List<Message>> entry : reqMap.entrySet()) { if (entry.getKey() != pid && !entry.getValue().isEmpty()) { if (!isFirstEarlier(myMessage, entry.getValue().get(0))) { return; } } } // remove this request message final Message firstMsg = reqMap.get(pid).remove(0); workingPool.execute(new Runnable() { public void run() { coordinator.acquire(firstMsg.getMsgId(), pid, firstMsg.getTimestamp()); // emulate owning resources for a long time try { Thread.sleep(50L); // rule 3 爲了釋放資源,進程A移除全部(Tm:A)的請求消息,而後發送帶時間戳的A釋放資源請求消息給其餘全部的進程程 coordinator.release(firstMsg.getMsgId(), pid, firstMsg.getTimestamp()); Message releaseMsg = new Message(pid, firstMsg.getMsgId(),MessageType.RELEASE_RES, clock.time()); sendToOtherProcesses(releaseMsg); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }