多线程出现后,最大的问题就是对资源的竞争如何保证同步的状态。java中同步的办法有很多。通过以下几个代码示例来看JAVA多线程同步状态保持机制。
首先来看无同步状态下 多线程和单线程执行情况,代码示例如下:
package sychonizedDemo;
import java.util.concurrent.CountDownLatch;
public class NomalSeqTask {
public static void main(String[]args){
CountDownLatch doneSignal = new CountDownLatch(20);
AddOne addOne = new AddOne("addOne",doneSignal);
System.out.println("Result of addOne Thread is as follows");
for(int i=0;i<20;i++)
new Thread(addOne).start();
try {
doneSignal.await();
} catch (InterruptedException e) {
}
System.out.println();
System.out.println("Result of addOneInSeq Thread is as follows");
AddOneInSeq addOneInSeq = new AddOneInSeq("addOneInSeq");
for(int i=0;i<20;i++)
addOneInSeq.add();
}
}
class AddOne extends Thread{
private static int count;
private CountDownLatch doneSignal;
public AddOne(String name,CountDownLatch doneSignal) {
super(name);
this.doneSignal = doneSignal;
}
public void add(){
count++;
try {
this.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print(count +" ");
doneSignal.countDown();
}
public void run(){
add();
}
}
class AddOneInSeq {
private String name;
private static int count;
public AddOneInSeq(String name) {
this.name = name;
}
public void add(){
count++;
System.out.print(count+" ");
}
}
执行结果如下:
Result of addOne Thread is as follows
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
Result of addOneInSeq Thread is as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
原因分析:
由于多个线程共同访问AddOne中的count,这时候由于对资源的访问没有限制所以造成了数据上的不一致性,本来多个线程期望看到的结果都是自己的加1后结果,实际确如打印所以。而单线程的打印结果却是一致的。这里就突出了多线程引用时数据一致性的问题,也就是所谓的状态同步。
解决方法大致有以下几种:
第一,加上外观锁。
具体代码示例如下:
package sychonizedDemo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockDemo {
public static void main(String[]args){
System.out.println("Result of addOneThreadSafeByLock Thread is as follows");
AddOneThreadSafeByLock addOneThreadSafeByLock = new AddOneThreadSafeByLock("addOneThreadSafeByLock");
for(int i=0;i<20;i++)
new Thread(addOneThreadSafeByLock).start();
}
}
class AddOneThreadSafeByLock extends Thread{
private static int countThreadSafe;
private Lock lock = new ReentrantLock();
public AddOneThreadSafeByLock(String name) {
super(name);
}
public void add(){
lock.lock();
try{
countThreadSafe++;
System.out.println(countThreadSafe);
}catch(Exception e){
lock.unlock();
}finally{
lock.unlock();
}
}
public void run(){
add();
}
}
执行结果如下:
Result of addOneThreadSafeByLock Thread is as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
第二,加上synchronized。
package sychonizedDemo;
public class SynchronizedMethod {
public static void main(String[]args){
System.out.println("Result of addOneThreadSafe Thread is as follows");
AddOneThreadSafe addOneThreadSafe = new AddOneThreadSafe("addOneThreadSafe");
for(int i=0;i<20;i++)
new Thread(addOneThreadSafe).start();
}
}
class AddOneThreadSafe extends Thread{
private static int countThreadSafe;
public AddOneThreadSafe(String name) {
super(name);
}
public synchronized void add(){
countThreadSafe++;
System.out.println(countThreadSafe);
}
public void run(){
add();
}
}
执行结果同上。
第三,原子操作类。代码示例如下:
package sychonizedDemo;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
// 并不能保证连续返回的都是1-20
/**
* @author Administrator
* Atomic: volatile +CAS
* situable for mild and moderate competition
*/
public class AtomicDemo {
public static void main(String[]args){
System.out.println("Result of addOneThreadSafeByAtomicInteger Thread is as follows");
CountDownLatch doneSignal = new CountDownLatch(20);
AddOneThreadSafeByAtomicInteger addOneThreadSafeByAtomicInteger = new AddOneThreadSafeByAtomicInteger("addOneThreadSafeByAtomicInteger",doneSignal);
Thread t = null;
for(int i=0;i<20;i++){
t = new Thread(addOneThreadSafeByAtomicInteger);
t.setName("addOneThreadSafeByAtomicInteger-"+i);
t.start();
}
try {
doneSignal.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(String name : addOneThreadSafeByAtomicInteger.getResultMap().keySet()){
System.out.println(name+ " value is "+addOneThreadSafeByAtomicInteger.getResultMap().get(name));
}
}
}
class AddOneThreadSafeByAtomicInteger extends Thread{
private static AtomicInteger countAtomicInteger = new AtomicInteger(0);
private static Map<String,Integer> resultMap = new ConcurrentHashMap<String,Integer>();
public Map<String, Integer> getResultMap() {
return resultMap;
}
public static void setResultMap(Map<String, Integer> resultMap) {
AddOneThreadSafeByAtomicInteger.resultMap = resultMap;
}
private CountDownLatch doneSignal;
public static AtomicInteger getCountAtomicInteger() {
return countAtomicInteger;
}
public static void setCountAtomicInteger(AtomicInteger countAtomicInteger) {
AddOneThreadSafeByAtomicInteger.countAtomicInteger = countAtomicInteger;
}
public AddOneThreadSafeByAtomicInteger(String name,CountDownLatch doneSignal) {
super(name);
this.doneSignal = doneSignal;
}
public int addOneByAtomicInteger(){
//循环 CAS 返回
for(;;) {
int current = countAtomicInteger.get();
int next = current+1;
if(countAtomicInteger.compareAndSet(current, next))
return next;
}
}
public void run(){
resultMap.put(this.getName()+doneSignal.getCount(), this.addOneByAtomicInteger());
doneSignal.countDown();
}
}
结果如下:
Result of addOneThreadSafeByAtomicInteger Thread is as follows
addOneThreadSafeByAtomicInteger15 value is 6
addOneThreadSafeByAtomicInteger16 value is 5
addOneThreadSafeByAtomicInteger3 value is 18
addOneThreadSafeByAtomicInteger4 value is 17
addOneThreadSafeByAtomicInteger14 value is 7
addOneThreadSafeByAtomicInteger9 value is 12
addOneThreadSafeByAtomicInteger2 value is 19
addOneThreadSafeByAtomicInteger12 value is 9
addOneThreadSafeByAtomicInteger8 value is 13
addOneThreadSafeByAtomicInteger7 value is 15
addOneThreadSafeByAtomicInteger13 value is 8
addOneThreadSafeByAtomicInteger10 value is 11
addOneThreadSafeByAtomicInteger20 value is 1
addOneThreadSafeByAtomicInteger5 value is 16
addOneThreadSafeByAtomicInteger19 value is 2
addOneThreadSafeByAtomicInteger11 value is 10
addOneThreadSafeByAtomicInteger18 value is 3
addOneThreadSafeByAtomicInteger1 value is 20
addOneThreadSafeByAtomicInteger17 value is 4
原因分析:由于原子操作类没有采取起始锁资源的方式,所以与前两种方式比较,它执行的结果保证了数据的一致性,却不保证线程执行的顺序性(大致原因比如在cas时,2号线程与1号线程冲突,这时候重复循环,但此时3号线程刚好CAS为真了,所以3号线程就可能先执行我拿了,还有就是在加入结果map时,如果不幸的1号线程正锁住了一个小区在添加,2号线程也恰好杯具的映射到这个小区,那么2号结果就要在后加入了)。这种操作的优势在于,减少了锁资源的开销,有利于并发。而第一,第二种方式都是锁住了资源导致,在共享这个临界资源时是一个排队使用的情况,这里就有可能成为并发性能的瓶颈之一了。
第四种,volatile方式。
具体代码示例如下:
package sychonizedDemo;
public class VolatileDemo {
public static void main(String[] args){
AndOneByVolatile andOneByVolatile = new AndOneByVolatile("AndOneByVolatile");
Thread t = null;
for(int i=0;i<20;i++){
t = new Thread(andOneByVolatile);
t.setName("andOneByVolatile-"+i);
t.start();
}
}
}
class AndOneByVolatile extends Thread{
private String name;
public static volatile int countVolatile;
public AndOneByVolatile(String name) {
this.name = name;
}
public void add(){
countVolatile++;
System.out.print(countVolatile+" ");
}
public void run(){
add();
}
}
执行结果略,使用与状态之类改变能为其他线程所知,此关键字相当于将线程的调用设置为引用,改的都是同一个值所以就会出现高并发下,一个线程由 500 +1 另外一个线程也由500+1最终造成累加结果与预期不一致的情况。
总结:
Lock :显示的外部加锁,可以有多个condition.
sychronized :Lock的简化版。保持资源。
volatile:保证了更改状态的可见性。
atomic类:通过volatile+cas的方式维持了一致性。适用于轻度和中度锁竞争的场合。
分享到:
相关推荐
使用临界区对象解决多个线程访问同一段内存数据同步问题
Core Data多线程大量数据同步,ios开发
多线程同步大量数据转录的多线程和同步
很不错的源码,3种多线程实现同步方法
基于多线程的QUdpSocket收发数据程序,界面上可以输入目标ip、port,与网络调试助手调试ok 欢迎下载,并指出程序中的问题,谢谢
某电信项目多线程同步数据实例,经生产测试,一分钟同步数据量20W
java 多线程导入excel数据,预防高并发,线程同步锁,
在Delphi中利用多线程实现数据采集的方法.doc
NoHttp核心架构之多线程通信、线程安全、线程同步;synchronized锁,Lock锁;具体讲解请移步:http://blog.csdn.net/yanzhenjie1003/article/details/50992468
在windows平台上建立的c++多线程demo,利用信号量实现线程同步功能。
几个多线程之间的互斥,同步;WPF主界面
多线程注意:wait()方法的调用要有判定条件常用 while () obj.wait(timeout, nanos); ... // Perform action appropriate to condition } synchronized会影响共享数据,但对其他语句的执行不会有规律了!
《秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据》 http://blog.csdn.net/morewindows/article/details/8646902 配套程序 在《秒杀多线程系列》的前十五篇中介绍多线程的相关概念,多线程同步互斥...
python 多线程的同步机制 以python2例程的方式讲解了python 多线程的同步 常用的方法,主要是锁、条件同步、队列 多线程的同步 多线程情况下最常见的问题之一:数据共享; 当多个线程都要去修改某一个共享数据...
设计一个多线程, 并且实现同步, 我理解的多线程需求如下: 1. 线程在Java端启动, 两个线程都调用C的方法 2. 有一个共同的数据, 被C的代码修改, 要求线程能对这个修改做同步, 即线程1
多线程不同步演示2,一个线程写数据,另一个线程读取数据,在没有同步的情况下,会出现什么问题?若你不知道,你可以看看该源码。
C#的多线程同步,C#中四种进程或线程同步互斥的控制方法
本代码介绍了如何给线程传递参数,以及用参数在主线程中显示数据
Java多线程数据同步处理的研究分析
在多线程编程中,需要注意的一些问题,如变量的共享、数据的同步、互斥等问题。如果不注意这些问题,可能会导致灾难性的后果。 LinuxThreads 库提供了一些多线程编程的关键函数,如 pthread_create() 函数、...