jedis解决高并发的一些学习

Posted 构建巨人肩膀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jedis解决高并发的一些学习相关的知识,希望对你有一定的参考价值。

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解决高并发的一些学习的主要内容,如果未能解决你的问题,请参考以下文章

Jedis干啥用的

并发处理学习

Web性能优化 高并发网站解决 单例

如何获得高并发的项目经验?

高并发学习

jedis连接redis