新建一个Spring Boot项目:
添加Web功能:
创建完成,测试是否可用:
可以使用。
创建annotations包,添加用于标注线程状态的四个注解:
1、线程安全的注解
package com.concurrency.example.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标注【线程安全】的类或方法的注解
* Created with IDEA
* author:LuXiaoWei
* Date:2018/5/5
* Time:13:19
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ThreadSafe {
String value() default "";
}
2、线程不安全的注解
package com.concurrency.example.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标注【线程不安全】的类或方法的注解
* Created with IDEA
* author:LuXiaoWei
* Date:2018/5/5
* Time:13:21
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NotThreadSafe {
String value() default "";
}
3、推荐写法的注解
package com.concurrency.example.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标注【推荐写法】的类或方法的注解
* Created with IDEA
* author:LuXiaoWei
* Date:2018/5/5
* Time:13:22
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Recommend {
String value() default "";
}
4、不推荐写法的注解
package com.concurrency.example.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标注【不推荐的写法】的类或方法的注解
* Created with IDEA
* author:LuXiaoWei
* Date:2018/5/5
* Time:13:23
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NotRecommend {
String value() default "";
}
并发模拟测试的方法:
1、PostMan软件测试
2、Apache Bench测试
3、JMeter压力测试
4、代码测试
新增一个用于测试的Controller并启动服务测试是否可用:
测试成功。
使用代码做并发模拟:
1、CountDownLatch类
如图所示,当线程A调用await()方法后。线程A进入等待状态,随后随着其他线程执行countDown方法时,计数器count的值会递减,当计数器变为0之后,线程A继续执行。
2、Semaphore类
控制同一时间可执行的线程数。
CountDownLatch适合执行完所有线程后进行一些操作,Semaphore适合控制同一时间线程并发数。
使用这两个类进行测试:
新建一个测试类concurrencyTest(线程不安全):
package com.concurrency.example;
import ch.qos.logback.core.net.SyslogOutputStream;
import com.concurrency.example.annotations.NotThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.*;
/**
* Created with IDEA
* author:LuXiaoWei
* Date:2018/5/5
* Time:13:53
*/
@Slf4j
@NotThreadSafe
public class ConcurrencyTest {
//总请求数
private static int clientTotal = 1000;
//同时并发执行的线程数
private static int threadTotal = 50;
private static int count = 0;
public static void main(String[] args) throws Exception{
//定义一个线程池
ExecutorService executorService = Executors.newCachedThreadPool();
//定义信号量
final Semaphore semaphore = new Semaphore(threadTotal);
//定义计数器
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i =0;i<clientTotal;i++){
executorService.execute(() ->{
try {
semaphore.acquire();
add();
semaphore.release();
}
catch (Exception e){
log.error("exception:",e);
}
//计数器进行减一操作
countDownLatch.countDown();
});
}
//确保全部请求执行完
countDownLatch.await();
//关闭线程池
executorService.shutdown();
//输出计数器的值
log.info("count:{}",count);
}
//对计数器进行+1操作
private static void add(){
count++;
}
}
多次执行该类,可发现结果并不相同,因为我跑的时候电脑开的软件比较多,电脑配置也不是太好,经常出现1000,998,999的情况,正常来说,电脑配置好的该值会越小。