1. 程式人生 > >jedis解決高並發的一些學習

jedis解決高並發的一些學習

transacti com action rri 有一個 urn ans list stat

1、高並發帶來的問題就是 {公共資源 } 的讀寫不準確

2、解決高並發的幾種場景:

  場景一)  同一個JVM進程(jee中就是同一個tomcat)中,公共資源在同一塊內存中,使用synchronized關鍵字給代碼塊或是方法加鎖,使得同一個代碼塊不會被同時調用;成員變量的數據類型盡量使用JUC中的atomic*等原子類,其中的方法都是原子操作,但是性能會有所降低;對於非原子類成員變量修飾符可以使用volatile(強制使用主存變量)。

    說明:JUC在此場景中的使用非常廣泛,主要是CAS操作,而且多線程的公共資源都是在主存中進行讀取,不會在寄存器中做修改;但是,會有一個ABA問題(比如說一個線程one從內存位置V中取出A,這時候另一個線程two也從內存中取出A,並且two進行了一些操作變成了B,然  後two又將V位置的數據變成A,這時候線程one進行CAS操作發現內存中仍然是A,然後one操作成功)

  場景二)  非同一個JVM進程(集群或分布式),公共資源在第三方緩存中(如redis),JUC的CAS操作會失效,這個時候想實現公共資源的正確調用只能依賴第三方的同步鎖機制(如redis的WATCH監控和事務MULTI-EXEC的配合使用)

3、實際應用:jedis解決搶購的問題:

package com.thinkgem.jeesite;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import
redis.clients.jedis.Transaction; import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2017/9/29. */ public class JedisMainTest { static final JedisPool pool = new JedisPool(new JedisPoolConfig() {{ setMaxIdle(
1000); setMaxTotal(1000); setTestOnBorrow(true); }}, "127.0.0.1", 6379); static final String watchkeys = "watchKeys";// 監視keys static final String goodsStore = "goodsStore";//庫存的key static final int stores = 10;//庫存量 public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(1000); ExecutorService executor1 = Executors.newFixedThreadPool(1000); Jedis jedis = pool.getResource(); jedis.set(watchkeys, "0");// 重置watchkeys為0 jedis.set(goodsStore,""+stores); jedis.del("setsucc", "setfail");// 清空搶成功的,與沒有成功的 jedis.close(); for (int i = 0; i < 10000; i++) {// 測試一萬人同時訪問 executor.execute(new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } for (int c = 0; c < 10; c++) { executor1.execute(new MyRunnable()); } } }); // Thread.sleep(50); } executor.shutdown(); } static class MyRunnable implements Runnable { /*TODO:未解決問題,一開始有兩個以上的線程同時執行,會出現庫存有剩余,但是同時執行的程序搶不到庫存*/ Jedis jedis = pool.getResource(); public MyRunnable() { } @Override public void run() { try { jedis.watch(watchkeys);// 開始監視鎖 String val = jedis.get(goodsStore); int valint = Integer.valueOf(val); String userifo = UUID.randomUUID().toString(); if (valint >0) { Transaction tx = jedis.multi();// 開啟事務 tx.decr(goodsStore);//庫存量 -1 tx.incr(watchkeys);//修改監控變量 List<Object> list = tx.exec();// 提交事務,如果此時watchkeys被改動了,則返回null //說明通過驗證了,即庫存還有剩余 if (list != null) { System.out.println("用戶:" + userifo + "搶購成功,當前搶購成功人數:" + (stores-valint+1)); /* 搶購成功業務邏輯 */ jedis.sadd("setsucc", userifo); Thread.sleep(900);//模擬業務執行時間 } else { System.out.println("用戶:" + userifo + "搶購失敗,其他線程幹擾"); /* 搶購失敗業務邏輯 */ jedis.sadd("setfail", userifo); Thread.sleep(400);//模擬業務執行時間 } } else { System.out.println("用戶:" + userifo + "搶購失敗,庫存以空"); jedis.sadd("setfail", userifo); Thread.sleep(400);//模擬業務執行時間 // Thread.sleep(500); return; } } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } } } }

jedis解決高並發的一些學習