多线程出现后,最大的问题就是对资源的竞争如何保证同步的状态。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的方式维持了一致性。适用于轻度和中度锁竞争的场合。
分享到:
相关推荐
标题"多线程数据同步"直指这一核心问题,而描述则具体提到了使用临界区对象作为解决方案之一。 线程同步是为了防止多个线程同时访问共享资源,导致数据的混乱。在Windows操作系统中,临界区对象是一种轻量级的同步...
在实现多线程数据转录的过程中,队列(`Queue<T>`)被用作数据结构来存储待处理的数据。队列是一种先进先出(FIFO)的数据结构,非常适合用于处理多线程环境中的任务调度。写入线程将数据添加到队列的尾部,而读取...
然而,多线程也带来了数据同步的问题,因为多个线程可能同时访问共享资源,如果不加以控制,就可能导致数据不一致或引发错误。本篇文章将深入探讨三种在C++中实现多线程同步的方法:事件对象、关键代码段和互斥对象...
### Core Data 多线程大量数据同步详解 #### 前言 在iOS开发中,Core Data 是一种广泛使用的持久层框架,它提供了一种面向对象的方式来存储和管理应用程序的数据。随着应用程序复杂度的增加,如何高效、稳定地管理...
然而,多线程编程也带来了一些挑战,其中之一就是如何确保线程安全,即在多线程环境下正确地共享数据。这里我们将深入探讨"多线程临界段同步"的概念,以及如何通过API方式实现它,而不是依赖MFC(Microsoft ...
在多线程编程中,线程同步是一种控制多个线程并发执行时访问共享资源的方式,以避免数据不一致和死锁等问题。以下是对线程同步的四种主要方式的详细解释: 1. **事件(Event)** 事件是Windows API提供的一种线程...
在提供的"ScanThread"文件名中,我们可以推测这是一个扫描线程的实现,可能是用来定时或按需扫描数据源,然后触发数据同步的过程。可能包含了线程启动、同步机制、数据处理逻辑等内容。 综上所述,这个电信项目实例...
综上所述,多线程导入Excel数据是一个涉及并发控制、线程同步、数据处理和性能优化的复杂过程。在具体实现时,要结合项目需求和资源限制,选择合适的策略和技术。例如,文件`BigdataTest.java`可能是实现上述功能的...
### 在Delphi中利用多线程实现数据采集的方法 #### 概述 本文档主要介绍了如何在Delphi环境中使用多线程技术实现数据采集的基本原理与实现步骤。Delphi是一种功能强大的开发工具,广泛应用于Windows应用程序开发。...
在编程领域,多线程是实现并发执行任务的重要方式,特别是在 Delphi 这样的面向对象的编程环境中。本文将深入探讨Delphi中的多线程和线程同步,并以"SortThreads"和"delphi-thread-gui"这两个示例项目为例,讲解如何...
多线程则是在一个进程中创建多个执行流,它们共享同一块内存空间,资源利用率高,但数据同步和互斥问题更复杂。在Linux中,可以使用`pthread_create()`创建线程,`pthread_join()`等待线程结束。线程间的同步互斥...
总之,C++的多线程功能使得开发者能够充分利用现代硬件的并行处理能力,而信号量作为一种有效的同步工具,可以防止数据竞争,确保程序的正确性。理解并掌握这些概念对于编写高效、可靠的多线程程序至关重要。
总结起来,C#的多线程机制允许我们创建并行执行的任务,通过线程互斥和同步保证数据一致性。而在WPF中,我们需谨慎处理UI更新,利用`Dispatcher`确保操作在正确的线程上执行。理解并熟练运用这些概念和技术,对于...
在编程领域,尤其是在Windows平台下开发C++应用时,多线程技术是非常关键的一部分,它允许程序同时执行多个任务,从而提升系统效率。...因此,对多线程同步的理解和应用能力是每个专业程序员必备的技能之一。
基于多线程的QUdpSocket收发数据程序,界面上可以输入目标ip、port,与网络调试助手调试ok 欢迎下载,并指出程序中的问题,谢谢
在PowerBuilder中实现多线程同步查询数据是一项高级技术,涉及到并发编程和数据库访问的优化。PowerBuilder是一款强大的第四代编程语言(4GL),尤其适用于开发数据库应用系统。本源程序的目标是提高应用程序的性能...
在IT领域,多线程是一种常见的编程技术,用于提高程序的执行效率,特别是在处理大量数据时。本示例中,我们关注的是如何在Delphi环境中使用TThread组件进行多线程编程,以便并行读取文本文件数据。下面将详细阐述这...
操作系统中的多线程同步是一个关键概念,特别是在并发编程中,它涉及到如何协调多个线程以避免数据不一致性和竞态条件。在这个实验中,我们关注的是C++编程语言中的实现,以及操作系统如何处理线程的优先级。 首先...
然而,多线程环境下也带来了一些问题,尤其是资源竞争和数据一致性问题,这些问题需要通过线程同步机制来解决。本文将详细介绍如何通过临界区、互斥内核对象、事件内核对象和信号量内核对象来实现线程同步。 1. ...
多线程同步机制在软件开发中扮演着至关重要的角色,特别是在多处理器系统或者并发执行的任务中,确保线程间的正确协作和数据一致性是必不可少的。VC++中提供了多种同步机制来处理多线程间的同步问题,其中Event是...