快看,i++真的不安全

上期文章講到「i++;」自己是一個線程不安全的操做,緣由是操做不是原子性的,存在取值和賦值的兩個過程,可是究竟怎麼會不安全呢?本期藉助一個「vmlens」的項目來演示爲什麼會發生線程不安全的狀況。文末是vmlens簡介。java

測試代碼:git

public class TestCounter {
	private volatile int i = 0;
	@Interleave
	public void increment() {
	 i++;	
	}
	@Test
	public void testUpdate() throws InterruptedException	{
		Thread first = new Thread( () ->   {increment();} ) ;
		Thread second = new Thread( () ->   {increment();} ) ;
		first.start();
		second.start();
		first.join();
		second.join();
		
	}	
	@After
	public void checkResult() {
		assertEquals( 2 , i );
	}	
}

重要的是pom.xml文件配置:apache

<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.vmlens</groupId>
  <artifactId>examples</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>examples</name>
  <url>http://maven.apache.org</url>

 <pluginRepositories>
  <pluginRepository>
    <id>vmlens</id>
    <url>http://vmlens.com/download</url>
  </pluginRepository>
</pluginRepositories>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
   		<dependency>
			<groupId>com.vmlens</groupId>
			<artifactId>annotation</artifactId>
			<version>1.0.2</version>
			<scope>test</scope>
		</dependency>
  
  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
   <build>
    <pluginManagement>
    <plugins>
    
     
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
 </pluginManagement>
 
  <plugins>
  			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>3.0.0-M3</version>
				<configuration>
					<includes>
						<include>none</include>
					</includes>
				</configuration>
			</plugin>
 	<plugin>
				<groupId>com.vmlens</groupId>
				<artifactId>interleave</artifactId>
				<version>1.0.4</version>
				<!-- start regression test -->
				<configuration>
					<trimStackTrace>false</trimStackTrace>
									<includes>
		<include>com.vmlens.examples.doNotCombine.TestCounter</include>
					</includes>
				</configuration>
           </plugin>
      </plugins>
  </build>
  </project>

接下來是vmlens的報告: api

從圖中咱們能夠看出在兩個線程同時執行「i++;」的時候,兩個線程都前後讀取到了i的值「0」,而後前後完成了計算「i+1」,最後又前後給i賦值「1」,致使測試用例執行失敗。安全

介紹一下這個插件: 「vmlens」是一款測試java多線程的工具。markdown

  1. 須要測試多個線程訪問相同內存位置或監視器的應用程序的全部部分。vmlens顯示多個線程訪問相同內存位置或監視器的全部位置。
  2. vmlens插入等待,在測試期間通知指令並從新運行測試,直到測試全部線程交錯。這與數據競爭和死鎖的自動檢測一塊兒致使系統和可重複的測試。
  3. 經過查看多個線程以何種方式訪問​​相同狀態,您能夠減小共享狀態的數量。
  4. 較少共享狀態意味着須要較少的同步監視器。

下面是做者托馬斯原文:多線程

Hello!

Do you love to write bug-free software? Me too!

It always bothers me when I can not test something. That's why I created vmlens, a tool to test multithreaded java.

Now 4 years and countless tests later vmlens enables you to test multi-threaded java systematic and reproducible. And like vmlens now let my completely test vmlens, vmlens let you test the multithreaded part of your application

Enjoy writing concurrent software secured by tests.

Cheers, Thomas

做者本人照片:app

歡迎有興趣的童鞋一塊兒交流less

相關文章
相關標籤/搜索