2016-12-25 14 views
6

Вот код, я наткнулся на:Должны ли быть синхронизированы операции с ThreadLocal?

class TransactionContextHolder { 

private static final ThreadLocal<TransactionContext> currentTransactionContext = new NamedInheritableThreadLocal<TransactionContext>(
    "Test Transaction Context"); 


static TransactionContext getCurrentTransactionContext() { 
    return currentTransactionContext.get(); 
} 

static void setCurrentTransactionContext(TransactionContext transactionContext) { 
    currentTransactionContext.set(transactionContext); 
} 

static TransactionContext removeCurrentTransactionContext() { 
    synchronized (currentTransactionContext) { 
     TransactionContext transactionContext = currentTransactionContext.get(); 
     currentTransactionContext.remove(); 
     return transactionContext; 
    } 
} 

}

currentTransactionContext поле имеет тип ThreadLocal и это единственное поле в классе.

Мне кажется, что синхронизация здесь не нужна, потому что значение, хранящееся в ThreadLocal, связано с конкретным потоком и, следовательно, не является общим состоянием. Кроме того, я думаю, что это влияет на производительность, поскольку currentTransactionContext сам по себе, и только один поток разрешен для входа в блок, в то время как многие могут делать это параллельно, не влияя на правильность.

Нужна ли синхронизация здесь?

+1

Просто убедитесь, что 'currentTransactionContext.initialValue' (или даже геттер) не имеет общее состояние, а затем вы должны быть отлично с удалением синхронизации. –

ответ

6

В общем, это трудно сделать гарантии о threadsafety данной только крошечная фрагмент программы, так как threadsafety этого свойство всей программы, и synchronized может координировать поведение во многих различных частях программы.

Например: может быть, есть еще какой-то фрагмент кода в другом месте, в котором используется сумасшедшее небезопасное отражение, чтобы попытаться проверить и/или мутировать кишки ThreadLocal, и поэтому это сломается, если вы будете мутировать ThreadLocal без блокировки?

Реально, однако, вы совершенно правы: никогда нет причин для синхронизации экземпляра ThreadLocal, кроме, быть может, внутри его метода initialValue. ThreadLocal сам по себе является механизмом обеспечения безопасности потоков, и он управляет его потоками безопасности лучше, чем вы могли бы получить, добавив synchronized в любом случае.

(Hat-наконечник, чтобы Margaret Bloom для указывая initialValue случая.)

+0

Точно. Единственным источником состояния гонки, о котором я могу думать, является метод ['initialValue'] (https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html#initialValue()) of 'ThreadLocal'. Это разделяется по всем потокам, и, как видно из примера в документе, связанного с ним, он должен использовать некоторую защиту. Этот метод вызывается 'get', так как он всегда выполняет' remove' после него (не знаю почему) –

+0

@MargaretBloom: Re: "они всегда выполняют' remove' после него (не знаю почему) ": Хорошо, что OP размещен методом 'removeCurrentTransactionContext', поэтому я думаю, что имеет смысл, что он всегда удаляет текущий контекст транзакции. – ruakh

+0

Правильно, я упустил имя метода :) «Убрать» имеет смысл, это «get», это подозрительно. Если контекст пока отсутствует, этот метод потенциально может создать новый, а затем удалить его. Но, как вы сказали: это всего лишь маленький фрагмент. –