慕课网高并发实战(三)- 项目准备

297 阅读4分钟

项目采用springboot基础框架快速开发,具体初始化方法不再赘述,不明白的可以看课程或者自行百度

1. 一些注解的准备

  • 线程安全注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 对于线程安全的类,加入一个@ThreadSafe注解的标示
 * @Target(ElementType.TYPE) 说明作用于类上
 * @Retention(RetentionPolicy.SOURCE) 指定注解作用的范围,在编译的时候就会被忽略掉
 * @author gaowenfeng
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ThreadSafe {
    String value() default "";
}

  • 线程不安全注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 用来标示[线程不安全的类]
 * @Target(ElementType.TYPE) 说明作用于类上
 * @Retention(RetentionPolicy.SOURCE) 指定注解作用的范围,在编译的时候就会被忽略掉
 * @author gaowenfeng
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NotThreadSafe {
    String value() default "";
}
  • 推荐写法注解

/**
 * 用来标记[推荐]的类或者写法
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Recommend {
    String value() default "";
}
  • 不推荐写法注解

/**
 * 用来标记[不推荐]的类或者写法
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NotRecommend {
    String value() default "";
}
  • ElementType 详解

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
   /** 声明注解作用在类,借口,枚举上*/
    TYPE,

    /** Field declaration (includes enum constants) */
   /** 声明注解作用在属性上*/
    FIELD,

    /** Method declaration */
   /** 声明注解作用在方法上*/
    METHOD,

    /** Formal parameter declaration */
   /** 声明注解作用在参数上*/
    PARAMETER,

    /** Constructor declaration */
   /** 声明注解作用在构造函数上*/
    CONSTRUCTOR,

    /** Local variable declaration */
   /** 声明注解作用在本地变量上*/
    LOCAL_VARIABLE,

    /** Annotation type declaration */
   /** 声明注解作用在注解上*/
    ANNOTATION_TYPE,

    /** Package declaration */
   /** 声明注解作用在包上*/
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
   /** 声明注解可以应用在TYPE声明上*/
    TYPE_PARAMETER,

    /**
     * Use of a type
     * Type.TYPE_USE 表示这个 Annotation 可以用在所有使用 Type 的地方(如:泛型,类型转换等)
     * @since 1.8
     */
    TYPE_USE
}
  • RetentionPolicy详解
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * 在编译的时候会被取消,只用于声明,理解,或者测试
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * 注解将被编译器记录在类文件中,但在运行时不需要由VM保留,(默认的选项)
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * 注解将被编译器记录在类文件中,但在运行时由VM保留,这样他们可以被反射获取(当你需要获取注解中字段的属性值的时候,需要用这个,比如AOP)
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

etentionPolicy.SOURCE仅仅是给应用层开发人员用的,RetentionPolicy.CLASS 需要应用层和底层系统开发人员配合使用的,所以仅仅是应用层开发的我们是一脸懵逼,意识CLASS和SOURCE的区别。(具体参考

2.并发模拟

  • 并发模拟工具

并发模拟工具

  • Postman:Http请求模拟工具

postman

  • Apache附带的工具

AB

# -n  总请求数
# -c  并发数
$ ab -n 1000 -c 50 http://localhost:8080/test
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:
Server Hostname:        localhost
Server Port:            8080

Document Path:          /test
Document Length:        4 bytes

# 并发量
Concurrency Level:      50
# 整个测试耗时
Time taken for tests:   0.285 seconds
# 完成的请求数
Complete requests:      1000
# 失败的请求数
Failed requests:        0
# 所有请求的相应数据的长度综合(HTTP相应数据的 头信息+正文数据的长度)(不包括请求的长度)
Total transferred:      136000 bytes
# 所有请求的相应数据中,正文相应的综合
HTML transferred:       4000 bytes
# 吞吐率(与并发数相关)(Complete requests/0.285 seconds)
Requests per second:    3505.09 [#/sec] (mean)
# 用户平均请求等待时间
Time per request:       14.265 [ms] (mean)
# 服务器平均请求等待时间
Time per request:       0.285 [ms] (mean, across all concurrent requests)
# 这些请求在单位时间内从服务器获取的数据长度(Total transferred/Time taken for tests)
Transfer rate:          465.52 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    5   2.7      5      13
Processing:     1    9   5.0      8      37
Waiting:        1    6   4.0      6      36
Total:          2   14   5.0     14      40

Percentage of the requests served within a certain time (ms)
  50%     14
  66%     15
  75%     16
  80%     17
  90%     19
  95%     21
  98%     30
  99%     34
 100%     40 (longest request)

  • JMeter

JMeter

创建线程组

创建HTTP请求

创建监视器

log

  • 并发模拟-代码

CountDownLatch

Semaphore

import com.gwf.concurrency.annoations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

/**
 * 并发测试
 * @author gaowenfeng
 */
@Slf4j
@NotThreadSafe
public class ConcurrencyTest {

    /** 请求总数 */
    public static int clientTotal = 5000;
    /** 同时并发执行的线程数 */
    public static int threadTotal = 50;

    public static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        // 创建线程池
        ExecutorService executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<>(), r -> new Thread(r,"测试线程"));
        // 信号量,闭锁
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        // 模拟并发请求
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(()->{
                try {
                    // 请求一个信号,如果信号量小于clientTotal,则阻塞
                    semaphore.acquire();
                    add();
                    // 释放一个信号
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("exception",e);
                }
                countDownLatch.countDown();
            });
        }
        // 阻塞直到countDown 的次数为threadTotal
        countDownLatch.await();
        // 关闭线程池
        executorService.shutdown();
        log.info("count:{}",count);

    }

    /**
     * 本质上应该是这个方法线程不安全
     */
    private static void add(){
        count++;
    }
}