2016-12-20 2 views
0

スレッドセーフの問題があるかどうかわからない シングルトンのutilクラスを使用していて、メンバ変数が最初に であるため、これらを避けるためにスレッドローカルを使用しました。問題。しかし、NettyのNIOスレッドプールは小さすぎます(サイズはわずか4でCPUコアは2です)。したがって、並行レベルが高い場合は、スレッドセーフの問題がいくつか存在します。シングルトンクラスのネットを使ってthreadlocalを使用する

  1. NIO-スレッド1はそれを扱う終了する前に、requestEが来るとNIO-スレッド1がrequestEを扱うようになり、

  2. を電子するThreadLocalの値を設定しrequestAの取り扱い、および

  3. にThreadLocalの値を設定されています

この状況では、requestAが流暢?もしこの値をメンバ変数として保持したいのであれば、それを避けるにはどうすればいいですか?(メソッドには入れません)

ありがとうございました!

/** 
* 
* @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

シングルトンはスレッドの安全性のために設計されていないため、変更可能な状態にしないでください。私はそのようなコードのために過去に深刻な問題を見てきました。私たちはこの習慣を強く奨励します。 –

+0

ありがとう、アナンド。だから私はあなたの提案は、方法で可変状態に置かれていると思いますか?しかしthreadlocalはスレッドの安全性に役立つか、それとも提案の方法ですか? –

+0

私はスレッドの安全性はあなたの問題ではないと思います。あなたはIO中に突然変異を起こすいくつかのデータを持っています。残念ながらNIOのおかげで、あなたはそのデータを共有する複数のスレッドを持っています。ですから、私が持っている質問は、なぜNIOを扱っているスレッドでThreadLocalが必要なのですか?私はいくつかのデザイン問題のにおいがします。 –

答えて

1

このようなシナリオでスレッドローカルを使用すると、同じスレッド内の複数のテナントによって使用されることが知られている場合、非常に危険です。私たちには、管理が簡単になる代替手段がありますが。 代わりのprivate ThreadLocal<byte[]> key = new ThreadLocal<byte[]>();あなたは

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

を使用することができますし、THREADLOCALを取得したいときはいつでも、その後、あなたは、対応するオブジェクトと同じようにアクセスすることができます。要求が行われるたびに異なるインスタンスを作成していることがわかっている場合はthisをキーとして使用することができます。そうでない場合はRequestなどの他の情報を使用して要求に対してキーをマッピングできます。

もちろん、threadlocalの代わりに静的なマップを使用することもできます。お役に立てれば。

+0

特に「あなたが同じスレッド内の複数のテナントによって使用されることがわかっていれば、非常に危険です」と言われました。感謝、もう一度ありがとう。 –

関連する問題