高并发,抢购

学生选课场景,跟抢购火车票类似。百度了一下,总结出4种方式

1.线程锁。加了 synchronized ,性能急剧下降。 java 本身就是多线程的,你把它单线程使用,不是明智的选择。 同时,如果分布式部署的时候,加了 synchronized 也无法控制并发。

2.数据库锁。乐观锁,悲观锁。基于数据库乐观锁面对的场景是并发量低,用户活跃度较低的场景, 主要考察的是数据库磁盘的读写能力,并发能力在 300-700 ,随着硬盘速度的提升,有可能会有所提高。

3.缓存(基于内存数据库的异步写入)redis或者memcached

4.利用消息中间件和缓存实现

基于Redis

import java.util.List;

import java.util.Random;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class MyRunnable implements Runnable {
    String watchkeys = "total"; //监视keys
    int total; //商品总数
    Jedis redis = new Jedis("127.0.0.1");
    String userinfo;

    public MyRunnable() {
    }


    public MyRunnable(String userinfo, int count) {
        this.userinfo = userinfo;
        this.total = count;
    }

    public static void main(String[] args) {
        int total = 50;
        final Jedis redis = new Jedis("127.0.0.1");
        redis.set("total", String.valueOf(total)); //设置商品总数
        //redis.del("setsucc", "setfail");
        redis.close();
        //创建用户,设置商品总数,然后开始抢购
        ExecutorService executor = Executors.newFixedThreadPool(20); //最大并发数(⊙o⊙)…
        for (int i = 0; i < 1000; i++) { //抢购人数
            executor.execute(new MyRunnable("user" + getRandomString(6),
                                            total));
        }
        executor.shutdown();
    }

    @Override
    public void run() {
        redis.watch(watchkeys);
        int num = Integer.valueOf(redis.get(watchkeys));
        if (num >= 1 && num <= total) {
            Transaction tx = redis.multi(); //开启事务
            tx.incrBy(watchkeys, -1); //增量为-1
            List list = tx.exec(); //提交事务,如果此时watchkeys被改动,则返回null
            if (list == null || list.size() == 0) {
                String failUser = "fail" + userinfo;
                String failInfo = "用户:" + failUser + "抢购失败";
                System.out.println(failUser);
                redis.setnx(failUser, failInfo); //抢购失败业务逻辑
            } else {
                for (Object obj : list) {
                    String succUser = "succ" + obj.toString() + userinfo;
                    String succInfo =
                        "用户:" + succUser + "抢购成功,当前抢购人数" + (1 - (num - total));
                    System.out.println(succInfo);
                    redis.setnx(succUser, succInfo); //抢购成功业务逻辑
                }
            }
        } else {
            String failUser = "kcfail" + userinfo;
            String failInfo = "用户:" + failUser + "商品抢购失败";
            System.out.println(failUser);
            redis.setnx(failUser, failInfo); //抢购失败业务逻辑
            return;
        }
        redis.close();
    }

    private static String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}

猜你喜欢

转载自my.oschina.net/u/3646781/blog/1617492