tianyunperfect 4 年 前
コミット
421a65f264

+ 96 - 0
.gitignore

@@ -0,0 +1,96 @@
+# Created by .ignore support plugin (hsz.mobi)
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/
+*.iml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Java template
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+

+ 23 - 0
pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.alvin.tps</groupId>
+    <artifactId>tps</artifactId>
+    <packaging>pom</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <modules>
+        <module>tps-common</module>
+        <module>tps-main</module>
+    </modules>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.0.3.RELEASE</version>
+        <relativePath/>
+    </parent>
+
+</project>

+ 22 - 0
tps-common/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tps</artifactId>
+        <groupId>com.alvin.tps</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>tps-common</artifactId>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 5 - 0
tps-common/src/main/java/com/alvin/tps/common/service/Job.java

@@ -0,0 +1,5 @@
+package com.alvin.tps.common.service;
+
+public interface Job {
+    void execute() throws Exception;
+}

+ 145 - 0
tps-common/src/main/java/com/alvin/tps/common/service/TpsService.java

@@ -0,0 +1,145 @@
+package com.alvin.tps.common.service;
+
+import com.alvin.tps.util.PropertiesUtil;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * tps服务
+ *
+ * @author 田云
+ * @date 2021/01/23
+ */
+public class TpsService {
+
+    /**
+     * 线程数量
+     */
+    private Integer n_threads;
+
+    /**
+     * 30 秒总时间
+     */
+    private Integer n_totalTime;
+
+    /**
+     * 用原子变量来统计执行时间,便于作原子递减
+     */
+    private AtomicInteger totalTime;
+
+    /**
+     * 用于统计执行的事物总数,用原子方式累加记录
+     */
+    private AtomicLong totalExecCount;
+    private AtomicLong totalExecTime;
+
+    /**
+     * 需要到等到所有线程都在同一起跑线,才开始统计计数,类似于发令枪
+     */
+    private CyclicBarrier barrier;
+
+    /**
+     * 执行时间到达时,所有的线程需要依次退出,主线程才开始统计执行事物总数
+     */
+    private CountDownLatch countDownLatch;
+
+    /**
+     * 线程执行标记 , 用volatile修饰,使变量修改具有线程可见性
+     */
+    private volatile boolean running;
+
+    /**
+     * 用线程池来执行统计
+     */
+    private ExecutorService executorService;
+
+    /**
+     * tps服务
+     */
+    public TpsService(Integer n_threads, Integer n_totalTime) {
+        this.n_threads = n_threads;
+        this.n_totalTime = n_totalTime;
+
+        this.totalTime = new AtomicInteger(this.n_totalTime);
+        this.totalExecCount = new AtomicLong(0L);
+        this.totalExecTime = new AtomicLong(0L);
+        this.barrier = new CyclicBarrier(this.n_threads);
+        this.countDownLatch = new CountDownLatch(this.n_threads);
+        this.running = true;
+    }
+
+    class Worker implements Runnable {
+        private Job job;
+        // 每个线程执行的事物统计量
+        int innerCount = 0;
+
+        public Worker(Job job) {
+            this.job = job;
+        }
+
+        @Override
+        public void run() {
+            try {
+                barrier.await(); // 等到所有线程都在起跑线
+                while (running) {
+                    try {
+                        // 单个job可能会超时,或者报异常
+                        long start = System.currentTimeMillis();
+                        this.job.execute();
+                        totalExecTime.addAndGet(System.currentTimeMillis() - start);
+                        innerCount++;
+                    } catch (Exception e) {
+                        System.out.println("线程Id:" + Thread.currentThread().getId() + " " + e.getMessage());
+                    }
+                }
+            } catch (Exception e) {
+                System.out.println("线程Id:" + Thread.currentThread().getId() + " " + e.getMessage());
+            } finally {
+                System.out.println("线程Id:" + Thread.currentThread().getId() + " 执行事物次数为:" + innerCount);
+                totalExecCount.getAndAdd(innerCount);
+                // 线程结束后,依次计数, 便于主线程继续执行
+                countDownLatch.countDown();
+            }
+
+        }
+    }
+
+    public void run(Job job) throws Exception {
+
+        executorService = Executors.newFixedThreadPool(this.n_threads); // 新建固定大小线程的池子
+        for (int i = 0; i < this.n_threads; i++) {
+            executorService.submit(new Worker(job)); // 提交线程到池子中
+        }
+        // 还需要一个线程,用于周期检查执行时间是否到达
+        final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+        scheduledExecutorService.scheduleAtFixedRate(() -> {
+            if (totalTime.decrementAndGet() == 0) { // 执行时间递减到0
+                running = false; // 告诉线程,时间到了,所有线程不再执行
+                scheduledExecutorService.shutdownNow();
+            }
+        }, 1L, 1L, TimeUnit.SECONDS);
+
+        // 主线程等到所有的线程都退出,则开始统计
+        countDownLatch.await();
+
+        long totalExeCount = totalExecCount.get();
+        System.out.println(this.n_threads + " 个线程," + this.n_totalTime + " 秒内总共执行的事物数量:" + totalExeCount);
+
+        long tps = totalExeCount / this.n_totalTime;
+        long perSecond = totalExecTime.get() / totalExeCount;
+        System.out.println("===============================================");
+        System.out.println("TPS: " + tps + ";平均每次耗时ms:" + perSecond);
+        System.out.println("===============================================");
+        executorService.shutdownNow(); // 关闭线程池
+    }
+
+}

+ 36 - 0
tps-common/src/main/java/com/alvin/tps/util/PropertiesUtil.java

@@ -0,0 +1,36 @@
+package com.alvin.tps.util;
+
+import com.alvin.tps.common.service.TpsService;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class PropertiesUtil {
+    public static Properties getProperties(String fileName) {
+        try {
+            String outPath = System.getProperty("user.dir") + File.separator + "config" + File.separator + fileName;//先读取config目录的,没有再加载classpath的
+            if (!new File(outPath).exists()) {
+                outPath = System.getProperty("user.dir") + File.separator + fileName;
+            }
+            Properties properties = new Properties();
+            InputStream in = new FileInputStream(new File(outPath));
+            properties.load(in);
+            return properties;
+        } catch (IOException e) {
+            System.out.println(e.getMessage());
+            try {
+                Properties properties = new Properties();
+                InputStream in = TpsService.class.getClassLoader().getResourceAsStream(fileName);//默认加载classpath的
+                properties.load(in);
+                return properties;
+            } catch (IOException es) {
+                System.out.println(es.getMessage());
+                return null;
+            }
+        }
+    }
+
+}

+ 66 - 0
tps-main/pom.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>tps</artifactId>
+        <groupId>com.alvin.tps</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>tps-main</artifactId>
+
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <fork>true</fork>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alvin.tps</groupId>
+            <artifactId>tps-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.4</version>
+        </dependency>
+        <!-- 配置文件自动映射 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+</project>

+ 37 - 0
tps-main/src/main/java/com/alvin/tps/main/TpsApplication.java

@@ -0,0 +1,37 @@
+package com.alvin.tps.main;
+
+import com.alvin.tps.common.service.TpsService;
+import com.alvin.tps.main.service.impl.JobImpl;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import java.io.IOException;
+
+/**
+ * @author 田云
+ * @date 2021/01/23
+ */
+@SpringBootApplication
+public class TpsApplication implements CommandLineRunner {
+    /**
+     * n个线程
+     */
+    @Value("${tps.n_threads}")
+    private Integer n_threads;
+    /**
+     * n总时间
+     */
+    @Value("${tps.n_totalTime}")
+    private Integer n_totalTime;
+
+    public static void main(String[] args) {
+        SpringApplication.run(TpsApplication.class, args);
+    }
+
+    @Override
+    public void run(String... args) throws Exception {
+        new TpsService(n_threads, n_totalTime).run(new JobImpl());
+    }
+}

+ 22 - 0
tps-main/src/main/java/com/alvin/tps/main/service/impl/JobImpl.java

@@ -0,0 +1,22 @@
+package com.alvin.tps.main.service.impl;
+
+import com.alvin.tps.common.service.Job;
+
+/**
+ * impl工作
+ *
+ * @author 田云
+ * @date 2021/01/23
+ */
+public class JobImpl implements Job {
+    /**
+     * 执行
+     *
+     * @throws Exception 异常
+     */
+    @Override
+    public void execute() throws Exception {
+        Thread.sleep(2);
+        System.out.println("OK");
+    }
+}

+ 6 - 0
tps-main/src/main/resources/application.yml

@@ -0,0 +1,6 @@
+server:
+  port: 0
+
+tps:
+  n_threads: 10
+  n_totalTime: 5