博客
关于我
Java并发编程规则:有状态的线程安全对象在线程池中使用不一定就是线程安全的
阅读量:104 次
发布时间:2019-02-26

本文共 5424 字,大约阅读时间需要 18 分钟。

如题:Java并发编程规则>有状态的线程安全对象在线程池中使用不一定就是线程安全的。在线程安全里面我们可以用的几个关键字是:volatile、Synchronized,另外状态变量我们可以使用原子变量。如果我们在编写了一个状态安全的线程类后,却不慎地使用非线程安全的线程池,那么也会导致线程不安全问题产生。

安全基本概述

volatile的使用要求满足下面的两个条件:

1)对变量或者引用的写操作不依赖于变量或者引用的当前值(如果只有特定的单个线程修改共享变量,那么修改操作也是可以依赖于当前值);
2)该变量或者引用没有包含在其它的不变式条件中;
volatile最常见的错误使用场景是使用volatile来实现并发 i++; 错误的原因是,该操作依赖于 i 变量的当前值,他是在 i 变量的当前值的基础上加一,所以说他依赖于 i 的当前值。多个线程执行 i++; 会丢失更新。比如两个线程同时读到 i 的当前值8,都进行加一,然后写回,最终 i 的结果是 9,而不是我们期待的10,丢失了更新。那么原子变量的引入就是针对volatile的这个缺陷的!!!原子变量的修改操作允许它依赖于当前值,所以说”原子变量“是比volatile的语义稍微强化一点!他不仅具有volatile的可见性,同时对原子变量。

从Java 1.5开始引入了原子变量和原子引用:

java.util.concurrent.atomic.AtomicBoolean

java.util.concurrent.atomic.AtomicInteger

java.util.concurrent.atomic.AtomicLong

java.util.concurrent.atomic.AtomicReference

以及他们对应的数组:

java.util.concurrent.atomic.AtomicIntegerArray

java.util.concurrent.atomic.AtomicLongArray

java.util.concurrent.atomic.AtomicReferenceArray

注:synchronized关键字用的比较多,这里就不说明了。

编写一个状态安全的类

package com.boonya.thread;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;/** * 状态安全线程 *  * @package com.boonya.thread.StateSafeThread * @date   2017年3月22日  下午4:28:57 * @author pengjunlin * @comment    * @update */public class StateSafeThread extends Thread {	private static AtomicInteger atomicCount = new AtomicInteger(0);// 多线程:线程安全的	private volatile static AtomicInteger volatileAtomicCount = new AtomicInteger(0);// 多线程:线程安全的			@Override	public void run() {		final Object lock = new Object();  		for (int i = 0; i < 50000; i++) {              new Thread(new Runnable() {                                    @Override                  public void run() {                     synchronized (lock) {                	   // Nothing....				   }                   atomicCount.incrementAndGet();                     volatileAtomicCount.incrementAndGet();                  }              }).start();          }  		// 休息5秒, 保证线程中的计算完成          try {              TimeUnit.SECONDS.sleep(5);  //关键        } catch (InterruptedException e) {              e.printStackTrace();          }          System.out.println("Thread Name=====:"+this.getName());          System.out.println("线程并发执行对计数器累计5000次,看并发结果!");          System.out.println("atomicCount=" + atomicCount.get());          System.out.println("volatileAtomicCount=" + volatileAtomicCount.get());	}}

编写一个线程池测试类

package com.boonya.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import org.junit.Test;/** * 状态安全线程测试类 *  * @package com.boonya.thread.StateSafeThreadTest * @date   2017年3月22日  下午4:41:37 * @author pengjunlin * @comment    * @update */public class StateSafeThreadTest {		/**	 * 线程安全的	 * 	 * @MethodName: testByOneThread 	 * @Description: 	 * @throws	 */	@Test	public void testByOneThread(){				for (int i = 0; i < 5; i++) {			Thread thread=new StateSafeThread();			thread.start();		}				try {			Thread.sleep(30000);		} catch (InterruptedException e) {			e.printStackTrace();		}	}		/**	 * 线程安全的	 * 	 * @MethodName: testByThreadPool 	 * @Description: 	 * @throws	 */	@Test	public void testByThreadPool(){		Thread thread=null;		ExecutorService executorService=Executors.newFixedThreadPool(5);// 线程个数大于或等于线程个数时线程安全				for (int i = 0; i < 5; i++) {			thread=new StateSafeThread();			executorService.execute(thread);		}		/*Future future=executorService.submit(thread);				try {			System.out.println(future.get());		} catch (InterruptedException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		} catch (ExecutionException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		}*/				try {			executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);		} catch (InterruptedException e) {			e.printStackTrace();		}finally{			executorService.shutdown();		}			}		/**	 * 非线程安全的	 * 	 * @MethodName: testByThreadPool2 	 * @Description: 	 * @throws	 */	@Test	public void testByThreadPool2(){		Thread thread=null;		ExecutorService executorService=Executors.newFixedThreadPool(3);// 小于线程个数导致线程不安全						for (int i = 0; i < 5; i++) {			thread=new StateSafeThread();			executorService.execute(thread);		}		/*Future future=executorService.submit(thread);				try {			System.out.println(future.get());		} catch (InterruptedException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		} catch (ExecutionException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		}*/		try {			executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);		} catch (InterruptedException e) {			e.printStackTrace();		}finally{			executorService.shutdown();		}			}		/**	 * 线程安全的	 * 	 * @MethodName: testByThreadPool3	 * @Description: 	 * @throws	 */	@Test	public void testByThreadPool3(){		Thread thread=null;		ExecutorService executorService=Executors.newCachedThreadPool();						for (int i = 0; i < 5; i++) {			thread=new StateSafeThread();			executorService.execute(thread);		}		/*Future future=executorService.submit(thread);				try {			System.out.println(future.get());		} catch (InterruptedException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		} catch (ExecutionException e1) {			// TODO Auto-generated catch block			e1.printStackTrace();		}*/		try {			executorService.awaitTermination(30000, TimeUnit.MILLISECONDS);		} catch (InterruptedException e) {			e.printStackTrace();		}finally{			executorService.shutdown();		}			}}
注:可以测试运行查看结果,推荐使用缓存线程池。

转载地址:http://jeyu.baihongyu.com/

你可能感兴趣的文章
MySql中关于geometry类型的数据_空的时候如何插入处理_需用null_空字符串插入会报错_Cannot get geometry object from dat---MySql工作笔记003
查看>>
mysql中出现Incorrect DECIMAL value: '0' for column '' at row -1错误解决方案
查看>>
mysql中出现Unit mysql.service could not be found 的解决方法
查看>>
mysql中出现update-alternatives: 错误: 候选项路径 /etc/mysql/mysql.cnf 不存在 dpkg: 处理软件包 mysql-server-8.0的解决方法(全)
查看>>
Mysql中各类锁的机制图文详细解析(全)
查看>>
MySQL中地理位置数据扩展geometry的使用心得
查看>>
Mysql中存储引擎简介、修改、查询、选择
查看>>
Mysql中存储过程、存储函数、自定义函数、变量、流程控制语句、光标/游标、定义条件和处理程序的使用示例
查看>>
mysql中实现rownum,对结果进行排序
查看>>
mysql中对于数据库的基本操作
查看>>
Mysql中常用函数的使用示例
查看>>
MySql中怎样使用case-when实现判断查询结果返回
查看>>
Mysql中怎样使用update更新某列的数据减去指定值
查看>>
Mysql中怎样设置指定ip远程访问连接
查看>>
mysql中数据表的基本操作很难嘛,由这个实验来带你从头走一遍
查看>>
Mysql中文乱码问题完美解决方案
查看>>
mysql中的 +号 和 CONCAT(str1,str2,...)
查看>>
Mysql中的 IFNULL 函数的详解
查看>>
mysql中的collate关键字是什么意思?
查看>>
MySql中的concat()相关函数
查看>>