Переглянути джерело

高并发下如何保证数据的一致性常用方法测试代码Demo初始化

danyuandefine 4 роки тому
коміт
82d427201b

+ 112 - 0
.gitignore

@@ -0,0 +1,112 @@
+# ---> Java
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+# ---> Eclipse
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# TeXlipse plugin
+.texlipse
+
+# ---> JetBrains
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
+
+*.iml
+
+## Directory-based project format:
+.idea/
+# if you remove the above rule, at least ignore the following:
+
+# User-specific stuff:
+# .idea/workspace.xml
+# .idea/tasks.xml
+# .idea/dictionaries
+
+# Sensitive or high-churn files:
+# .idea/dataSources.ids
+# .idea/dataSources.xml
+# .idea/sqlDataSources.xml
+# .idea/dynamic.xml
+# .idea/uiDesigner.xml
+
+# Gradle:
+# .idea/gradle.xml
+# .idea/libraries
+
+# Mongo Explorer plugin:
+# .idea/mongoSettings.xml
+
+## File-based project format:
+*.ipr
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+
+#Svn
+.svn/
+#log
+*.log
+logs/
+*.log.*
+
+#target
+target/

Різницю між файлами не показано, бо вона завелика
+ 576 - 0
README.md


+ 47 - 0
pom.xml

@@ -0,0 +1,47 @@
+<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.danyuanblog.test.concurrent</groupId>
+	<artifactId>concurrent-count-demo</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>concurrent-count-demo</name>
+
+	<!-- 父构件坐标信息 -->
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.0.5.RELEASE</version>
+		<relativePath /> <!-- lookup parent from repository -->
+	</parent>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<java.version>1.8</java.version>
+	</properties>
+
+	<dependencies>
+		<!-- 引入spring boot web模块 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<!-- 引入spring boot测试模块 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+
+	
+</project>

+ 20 - 0
src/main/java/com/danyuanblog/test/concurrent/StartServer.java

@@ -0,0 +1,20 @@
+/**  
+* Title StartServer.java  
+* Description  
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class StartServer {
+
+	public static void main(String[] args) {
+		SpringApplication.run(StartServer.class, args);
+	}
+}

+ 37 - 0
src/main/java/com/danyuanblog/test/concurrent/test/AtomicCountController.java

@@ -0,0 +1,37 @@
+/**  
+* Title AtomicCountController.java  
+* Description  利用AtomicInteger保证线程安全的计数统计示例
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent.test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class AtomicCountController {
+	private AtomicInteger count = new AtomicInteger(0);
+	
+	/**
+	 * 查询统计结果
+	 * @author danyuan
+	 */
+	@GetMapping("/atomic/showResult")
+	public Integer showResult(){
+		return count.get();
+	}
+	
+	/**
+	 * 访问一次增加一次统计计数
+	 * @author danyuan
+	 */
+	@GetMapping("/atomic/addCount")
+	public void addCount(){//利用AtomicInteger的方法来保证原子性
+		count.incrementAndGet();
+	}
+}

+ 44 - 0
src/main/java/com/danyuanblog/test/concurrent/test/LockCountController.java

@@ -0,0 +1,44 @@
+/**  
+* Title LockCountController.java  
+* Description  利用ReentrantLock同步锁保证线程安全的计数统计示例
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent.test;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class LockCountController {
+	private Integer count = 0;
+	private Lock lock = new ReentrantLock();
+	
+	/**
+	 * 查询统计结果
+	 * @author danyuan
+	 */
+	@GetMapping("/lock/showResult")
+	public Integer showResult(){
+		return count;
+	}
+	
+	/**
+	 * 访问一次增加一次统计计数
+	 * @author danyuan
+	 */
+	@GetMapping("/lock/addCount")
+	public void addCount(){
+		lock.lock();
+		try {//使用加锁的方式保证请求串行计数
+			count++;
+		}finally{
+			lock.unlock();
+		}	
+	}
+}

+ 35 - 0
src/main/java/com/danyuanblog/test/concurrent/test/NotSafeCountController.java

@@ -0,0 +1,35 @@
+/**  
+* Title NotSafeCountController.java  
+* Description  线程不安全的计数统计示例
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent.test;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class NotSafeCountController {
+	private Integer count = 0;
+	
+	/**
+	 * 查询统计结果
+	 * @author danyuan
+	 */
+	@GetMapping("/showResult")
+	public Integer showResult(){
+		return count;
+	}
+	
+	/**
+	 * 访问一次增加一次统计计数
+	 * @author danyuan
+	 */
+	@GetMapping("/addCount")
+	public void addCount(){
+		count++;
+	}
+}

+ 37 - 0
src/main/java/com/danyuanblog/test/concurrent/test/SynchronizedCountController.java

@@ -0,0 +1,37 @@
+/**  
+* Title SynchronizedCountController.java  
+* Description  利用synchronized对象访问同步锁保证线程安全的计数统计示例
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent.test;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class SynchronizedCountController {
+	private Integer count = 0;
+	
+	/**
+	 * 查询统计结果
+	 * @author danyuan
+	 */
+	@GetMapping("/sync/showResult")
+	public Integer showResult(){
+		return count;
+	}
+	
+	/**
+	 * 访问一次增加一次统计计数
+	 * @author danyuan
+	 */
+	@GetMapping("/sync/addCount")
+	public void addCount(){
+		synchronized (this) {//使用加锁的方式保证请求串行计数
+			count++;
+		}		
+	}
+}

+ 66 - 0
src/main/java/com/danyuanblog/test/concurrent/test/ThreadLocalCountController.java

@@ -0,0 +1,66 @@
+/**  
+* Title ThreadLocalCountController.java  
+* Description  使用ThreadLocal保证多线程安全的计数统计示例
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent.test;
+
+import java.util.HashSet;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class ThreadLocalCountController {
+	private static HashSet<Counter> set = new HashSet<>();
+	private ThreadLocal<Counter> count = new ThreadLocal<Counter>(){
+		@Override
+		protected Counter initialValue() {
+			Counter counter = new Counter();
+			synchronized (set) {
+				set.add(counter);
+			}
+			counter.setCount(0);
+			return counter;
+		};
+	};
+	
+	class Counter{
+		private Integer count;
+
+		/**
+		 * @return the count
+		 */
+		public Integer getCount() {
+			return count;
+		}
+
+		/**
+		 * @param count the count to set
+		 */
+		public void setCount(Integer count) {
+			this.count = count;
+		}		
+	}
+	/**
+	 * 查询统计结果
+	 * @author danyuan
+	 */
+	@GetMapping("/threadLocal/showResult")
+	public Integer showResult(){
+		return set.stream().map(x -> x.getCount()).reduce(0, (a,b) ->  a + b);
+	}
+	
+	/**
+	 * 访问一次增加一次统计计数
+	 * @author danyuan
+	 */
+	@GetMapping("/threadLocal/addCount")
+	public void addCount(){//利用ThreadLocal实现分布式计算,每个线程自己统计自己的,避免上锁操作
+		Counter counter = count.get();
+		counter.setCount(counter.getCount()+1);
+	}
+}

+ 35 - 0
src/main/java/com/danyuanblog/test/concurrent/test/VolatileCountController.java

@@ -0,0 +1,35 @@
+/**  
+* Title VolatileCountController.java  
+* Description  利用volatile关键字保证线程安全的计数统计示例
+* @author danyuan
+* @date Mar 8, 2020
+* @version 1.0.0
+* site: www.danyuanblog.com
+*/ 
+package com.danyuanblog.test.concurrent.test;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class VolatileCountController {
+	private volatile Integer count = 0;
+	
+	/**
+	 * 查询统计结果
+	 * @author danyuan
+	 */
+	@GetMapping("/volatile/showResult")
+	public Integer showResult(){
+		return count;
+	}
+	
+	/**
+	 * 访问一次增加一次统计计数
+	 * @author danyuan
+	 */
+	@GetMapping("/volatile/addCount")
+	public void addCount(){
+			count++;
+	}
+}

+ 2 - 0
src/main/resources/application.yml

@@ -0,0 +1,2 @@
+server:
+  port: 8080