Java并发(3)--项目准备:环境初始化、案例准备、并发模拟工具、并发模拟代码

一 环境初始化

  1. 现在码云上建立新仓库 Concurrency ,我的Concurrency
  2. 通过 https://start.spring.io/ 新建 spring boot 项目 concurrency
  3. 在本地Git仓库把 码云项目拉下来 git clone https://gitee.com/libinliu/Concurrency.git
  4. 将 步骤2中的项目信息复制到 本地仓库中
    ==1==
  5. git push 到远程仓库

二 案例准备

自定义部分注解来描述我们后面写的类的一些特性:
ThreadSafe 注解表示线程安全的类或者写法
NotThreadSafe 注解表示线程不安全的类或者写法
Recommend 注解表示推荐的类或者写法
NotRecommend 注解表示不推荐的类或者写法

ThreadSafe类示例


package com.hust.concurrency.annoations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;



/**
* @Description 标记 [线程安全] 的类或者写法
* @since  2019年1月8日 下午2:29:03
* @author LiuLiBin
*/

//@Target 表示这个注解能放在什么位置上,是只能放在类上?还是即可以放在方法上,又可以放在属性上
//ElementType.TYPE :表示 能修饰类、接口或枚举类型
@Target(ElementType.TYPE) 

//@Retention 表示生命周期,
// RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就没了。@Override 就是这种注解

@Retention(RetentionPolicy.SOURCE)

public @interface ThreadSafe {

	/* 成员变量
	 * 1. 注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型
	 * 
	 * 2. 注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组
	 * 
	 * 3. 如果注解只有一个成员,则成员名必须取名为 value() ,在使用时可以忽略成员名和赋值号(=)
	 * 
	 * 4. 注解类可以没有成员,没有成员的注解称为标识注解
	 * */

	String value() default "";
}

三 并发模拟-工具

==2==

1. postman 并发测试步骤

  1. 新开接口 localhost:8080/test,在postman中测试接口访问通过后,将接口保存在左侧的Collections中
  2. 开始并发测试
    ==3==
    ==4==

2. Apache Bench 并发模拟的性能测试

ApacheBench 是 Apache 服务器自带的一个web压力测试工具,简称ab。ab又是一个命令行工具,对发起负载的本机要求很低,根据ab命令可以创建很多的并发访问线程,模拟多个访问者同时对某一URL地址进行访问,因此可以用来测试目标服务器的负载压力。总的来说ab工具小巧简单,上手学习较快,可以提供需要的基本性能指标,但是没有图形化结果,不能监控。

  1. 下载与安装
    Apache Bench(AB)的下载、安装与访问

  2. ab的用法1

    1. 首先,我们输入cmd打开DOS窗口,然后将更改当前工作目录为:Apache安装目录/bin/。然后键入帮助命令ab -help(或者ab /?、ab -h),我们就可以看到用法介绍界面。
    2. ab可以配置的参数选项比较多,但是,一般情况下我们只需要使用形如ab -n 数字 -c 数字 url路径的命令即可。譬如,我们对位于本地Apache服务器上、URL为localhost/index.php的页面进行压力测试。测试总次数为1000,并发数为100(相当于100个用户同时访问,他们总共访问1000次)。我们输入DOS命令ab -n 1000 -c 100 localhost/index.php
    Server Software:        Apache/2.2.25 (服务器软件名称及版本信息)
    Server Hostname:        localhost (服务器主机名)
    Server Port:            80 (服务器端口)
    Document Path:          /index.php (供测试的URL路径)
    Document Length:        10 bytes (供测试的URL返回的文档大小)
    Concurrency Level:      100 (并发数)
    Time taken for tests:   0.247 seconds (压力测试消耗的总时间)
    Complete requests:      1000 (压力测试的总次数)
    Failed requests:        0 (失败的请求数)
    Write errors:           0 (网络连接写入错误数)
    Total transferred:      198000 bytes (传输的总数据量)
    HTML transferred:       10000 bytes (HTML文档的总数据量)
    Requests per second:    4048.34 [#/sec] (mean) (平均每秒的请求数)
    Time per request:       24.701 [ms] (mean) (所有并发用户(这里是100)都请求一次的平均时间)
    Time per request:       0.247 [ms] (mean, across all concurrent requests) (单个用户请求一次的平均时间)
    Transfer rate:          782.78 [Kbytes/sec] received (传输速率,单位:KB/s)
    

3. JMeter 并发模拟的性能测试

JMeter安装+配置+运行

  1. JMeter 简单使用
    添加线程组
    ==5==
    填写线程组信息
    ==6==
    添加Http请求
    ==7==
    完善 Http请求
    ==8==
    添加监听器监视请求结果
    ==9==
    运行请求并分析结果
    ==10==

四 并发模拟-代码

使用 CountDownLatchSemaphore 来模拟并发2模型3

ConcurrencyTest


package com.hust.concurrency.service;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

import lombok.extern.slf4j.Slf4j;

/**
* @Description  使用 [CountDownLatch]和 [Semaphore] 和  [ExecutorService] 来模拟并发状态。
* @since  2019年1月8日 下午8:37:54
* @author LiuLiBin
*/
@Slf4j
public class ConcurrencyTest {
	
	//请求总数
	public static int clientTotal = 1000;
	
	//同时并发执行的线程数
	public static int threadTotal = 50;
	
	//测试并发 的计数值
	public static int count = 0 ;
	
	public static void main(String[] args) throws InterruptedException {
		
		//定义线程池
		ExecutorService executorService = Executors.newCachedThreadPool();
		
		//定义信号量 ,信号量为 50
		final Semaphore semaphore = new Semaphore(threadTotal);
		
		//定义计数器闭锁 ,期望所有请求请求完后统计计数结果 
		final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
		
		//放入请求,将请求线程全部放入线程池中
		for (int i = 0; i < clientTotal; i++) {

			executorService.execute(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
					try {
						semaphore.acquire(); // 获取一个许可
						add();
						semaphore.release(); // 释放一个许可
					} catch (Exception e) {

						log.error("exception", e);
					}
					countDownLatch.countDown(); // 计数器闭锁减1
				}
			});
		}
		
		//在所有线程请求执行完后 ,唤醒等待线程 ,此处涉及到countDownLatch 的实现机制
		countDownLatch.await();
		
		//关闭线程池
		executorService.shutdown();
		
		//打印计数值信息
		log.info("count:{}",count);
		
		
		
	}
	
	/**
	 * 增加计数值
	 */
	private static void add() {
		count++;
	}
}

运行上面代码会发现,计数值不是固定不变的


  1. ab压力测试 ↩︎

  2. CountDownLatch什么时候用 ↩︎

  3. Semaphore原理 ↩︎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值