簡體   English   中英

多線程-共享數據

[英]multithreading - sharing data

在采訪中有人問我以下問題。

有一個由多個線程共享的對象。 該對象具有以下功能。 您如何確保不同的線程可以針對參數x的不同值同時執行功能? 如果兩個線程以x的相同值執行,則應阻塞其中之一。

public void func(String x){
-----
}  

在這種情況下,“ synchronized”關鍵字將不起作用,因為它將確保一次只能執行一個線程。 請讓我知道這將是解決方案

我想到的第一件事是

public void func(String x){
    synchronized (x.intern()) {
        // Body here
    }
}  

這將像描述的那樣運行。 當然,這感覺像是一個討厭的黑客,因為同步的對象是可公開訪問的,因此其他代碼可能會干擾鎖定。

創建一個HashMap作為成員變量。

private HashMap<String,Lock> lockMap = new HashMap<String,Lock>();
public void func(String x){
    if(lockMap.get(x) == null){
        lockMap.put(x,new ReentrantLock());
    }  
    lockMap.get(x).lock(); 
    ...
    ...  
    lockMap.get(x).unlock(); 
}

面試官可能對Ernest Friedman-Hill提出的解決方案感興趣。 但是,由於其缺點,通常不能在生產代碼中使用它。 一旦我編寫了以下同步實用程序來解決此問題:

package com.paypal.risk.ars.dss.framework.concurrent;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;


public class MultiLock <K>{
    private ConcurrentHashMap<K, ReentrantLock> locks = new ConcurrentHashMap<K, ReentrantLock>();  

    /**
     * Locks on a given id.
     * Make sure to call unlock() afterwards, otherwise serious bugs may occur.
     * It is strongly recommended to use try{ }finally{} in order to guarantee this.
     * Note that the lock is re-entrant. 
     * @param id The id to lock on
     */
    public void lock(K id) {
        while (true) {
            ReentrantLock lock = getLockFor(id);
            lock.lock();
            if (locks.get(id) == lock)
                return;
            else // means that the lock has been removed from the map by another thread, so it is not safe to
                 // continue with the one we have, and we must retry.
                 // without this, another thread may create a new lock for the same id, and then work on it.
                lock.unlock();
        }
    }

    /**
     * Unlocks on a given id.
     * If the lock is not currently held, an exception is thrown.
     *  
     * @param id The id to unlock
     * @throws IllegalMonitorStateException in case that the thread doesn't hold the lock
     */
    public void unlock(K id) {
        ReentrantLock lock = locks.get(id);
        if (lock == null || !lock.isHeldByCurrentThread())
            throw new IllegalMonitorStateException("Lock for " + id + " is not owned by the current thread!");
        locks.remove(id);
        lock.unlock();
    }

    private ReentrantLock getLockFor(K id) {
        ReentrantLock lock = locks.get(id);
        if (lock == null) {
            lock = new ReentrantLock();
            ReentrantLock prevLock = locks.putIfAbsent(id, lock);
            if (prevLock != null)
                lock = prevLock;
        }
        return lock;
    }
}

請注意,可以使用簡單的映射和全局鎖以更簡單的方式實現它。 但是,我想避免全局鎖定,以提高吞吐量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM