2016-12-20 4 views
0

Я не уверен, существуют ли какие-либо проблемы с потоком безопасности . Я использую класс использования singleton, и во-первых, есть переменная-член, , я использовал threadlocal, чтобы избежать этих вопросы. Но нитевидный пул Nio netty слишком мал (размер всего 4, из-за ядра процессора 2), поэтому мне интересно, что существуют некоторые проблемы безопасности потоков, когда уровень параллельного уровня высокий, например:Использование threadlocal в одноэлементном классе в netty

  1. НИО-thread1 обрабатывает requestA и установите ThreadLocal значение в

  2. , прежде чем он закончил ее обработки, requestE приходит и НИО-thread1 приходит обрабатывать requestE и установите ThreadLocal значение е

Таким образом, в этой ситуации был requestA в fluenced? Если да, то как я могу избежать этого, если я хочу сохранить это значение в качестве переменной-члена (не помещать его в метод)

Спасибо за любое предложение!

Вот мой код:

/** 
* 
* @param <T> 
*   source 
* @param <V> 
*   result 
* @param <K> 
*   key 
*/ 
public interface BaseDecryption<S, R, K> { 

     public static enum DecryType { 
      AES128CBC, AES128XOR, XOR 
     } 

     public BaseDecryption<S, R, K> withDecryType(DecryType type); 

     public DecryType getDecryType(); 

     public R decrypt(S source); 

    } 


public abstract class BytesDecryption implements 
      BaseDecryption<byte[], byte[], byte[]> { 

     private DecryType decrypTye; 

     /** 
     * Here is where I used the treadLocal 
     * 
     */ 
     private ThreadLocal<byte[]> key = new ThreadLocal<byte[]>(); 

     protected DecryType getDecrypTye() { 
      return decrypTye; 
     } 

     protected byte[] getKey() { 
      return this.key.get(); 
     } 

     public BaseDecryption<byte[], byte[], byte[]> withDecryKey(byte[] key) { 
      this.key.set(key); 
      return this; 
     } 

     @Override 
     public BaseDecryption<byte[], byte[], byte[]> withDecryType(
       DecryType decryType) { 
      this.decrypTye = decryType; 
      return this; 
     } 

    } 

@Component("LEAD_AES128CBC") 
public class AES128CBC extends BytesDecryption { 

    private AlgorithmParameters params; 
    private static final String KEY_ALGORITHM = "AES"; 
    public static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding"; 
    private static final Logger logger = LoggerFactory 
      .getLogger(AES128CBC.class); 

    public AES128CBC() throws NoSuchAlgorithmException, 
      InvalidParameterSpecException { 
     Security.addProvider(new BouncyCastleProvider()); 
     this.withDecryType(DecryType.AES128CBC); 
     initVi(); 
    } 

    @Override 
    public byte[] decrypt(byte[] source) { 
     byte[] key = getKey(); 
     byte[] size16Key = new byte[16]; 
     System.arraycopy(key, 0, size16Key, 0, 16); 
     SecretKey secretKey = new SecretKeySpec(size16Key, KEY_ALGORITHM); 
     try { 
      Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 
      cipher.init(Cipher.DECRYPT_MODE, secretKey, params); 
      if (source.length % 16 != 0) { 
       byte[] encryptionBytes = new byte[source.length - source.length 
         % 16]; 
       System.arraycopy(source, 0, encryptionBytes, 0, 
         encryptionBytes.length); 
       byte[] decryptionBytes = cipher.doFinal(encryptionBytes); 
       byte[] finalBytes = new byte[decryptionBytes.length 
         + source.length % 16]; 
       System.arraycopy(decryptionBytes, 0, finalBytes, 0, 0); 
       // only multiple of 16 bytes will be decrypted, so copy the 
       // remained 
       System.arraycopy(source, encryptionBytes.length, finalBytes, 
         encryptionBytes.length, source.length % 16); 
       return finalBytes; 
      } 
      return cipher.doFinal(source); 
     } catch (NoSuchAlgorithmException | NoSuchPaddingException 
       | IllegalBlockSizeException | BadPaddingException 
       | InvalidKeyException | InvalidAlgorithmParameterException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    @Override 
    public DecryType getDecryType() { 
     return DecryType.AES128CBC; 
    } 

    public void initVi() throws NoSuchAlgorithmException, 
      InvalidParameterSpecException { 
     byte[] iv = new byte[16]; 
     Arrays.fill(iv, (byte) 0x00); 
     params = AlgorithmParameters.getInstance(KEY_ALGORITHM); 
     params.init(new IvParameterSpec(iv)); 
    } 

    public static byte[] hexStringToByteArray(String s) { 
     int len = s.length(); 
     byte[] data = new byte[len/2]; 
     for (int i = 0; i < len; i += 2) { 
      data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 
           + Character.digit(s.charAt(i+1), 16)); 
     } 
     return data; 
    } 
} 

и я использую пружине

BeanUtil.getBean(encryType) // encryType may equal to LEAD_AES128CBC 

, чтобы получить класс.

+2

Singletons не предназначены для обеспечения безопасности потоков, поэтому они не должны иметь изменяемых состояний. Из-за такого кода я видел серьезные проблемы в прошлом, и мы решительно отвергаем эту практику. –

+0

Спасибо, Ананд. Итак, я предполагаю, что ваше предложение помещает изменчивые состояния в метод? Но может ли threadlocal быть полезным для безопасности потоков или это способ? –

+0

Я думаю, что безопасность нитей не является вашей проблемой. У вас есть некоторые данные, которые мутируются во время ввода-вывода. и, к сожалению, из-за NIO у вас есть несколько потоков, которые используют эти данные. Так что у меня вопрос: ПОЧЕМУ вам нужен ThreadLocal в потоке, который обрабатывает NIO? Я чувствую запах какой-то проблемы с дизайном. –

ответ

1

Использование threadlocal в таком сценарии может быть чрезвычайно опасным, если известно, что такой код используется несколькими арендаторами в пределах одного потока. Хотя у нас есть альтернатива, которая может упростить управление. Вместо private ThreadLocal<byte[]> key = new ThreadLocal<byte[]>(); вы можете использовать

`private ThreadLocal<Map<Object, byte[]>> key = new ThreadLocal<Map<Object, byte[]>>(); 

и тогда, когда вы хотите, чтобы получить ThreadLocal, вы можете получить доступ к тому же с соответствующим объектом. Вы можете использовать в качестве своего ключа, если вы знаете, что создаете разные экземпляры для каждого сделанного запроса, иначе вы можете использовать любую другую информацию, такую ​​как Request, для сопоставления ключа с запросом.

Конечно, у вас есть возможность использовать статическую карту вместо threadlocal. Надеюсь это поможет.

+0

Это очень помогает мне, особенно вы сказали: «Очень опасно, если такой код, как известно, используется несколькими арендаторами внутри одного потока», я понял, что и то, что вы предлагаете, также делает смысл, еще раз спасибо. –

Смежные вопросы