如果对共享的可变数据不能同步访问,其后果是非常可怕的,即使这个变量是原子可读写的。
在一个线程中终止另一个线程时使用Thread.stop方法是不安全,使用它会遭到数据破坏。通常的做法是轮询一个boolean域:
public class TestCode { private static boolean stopRequested=false; public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(new Runnable() { public void run() { int i=0; while (!stopRequested) { i++; } } }); thread.start(); TimeUnit.SECONDS.sleep(1); stopRequested=true; } }
但是上述代码的问题在于由于没有同步,就不能保证后台线程何时”看到“主线程对stopRequested的值所做的改变,没有同步虚拟机就会将下面这种代码:
while (!stopRequested) { i++; }
优化成
while (!stopRequested) { while (true) i++; }
这个应该是所谓的指令重排序的以达到性能提升的目的,结果会导致程序失败。
正确的做法是同步访问stopRequested,代码如下:
public class TestCode { private static boolean stopRequested = false; public static synchronized boolean getStopRequested() { return stopRequested; } public static synchronized void stopRequest(){ stopRequested=true; } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { public void run() { int i = 0; while (!getStopRequested()) { i++; } } }); thread.start(); TimeUnit.SECONDS.sleep(1); stopRequest(); } }
synchronized关键字修饰以上两个方法只是为了达到同步的通信效果,而不是为了互斥,虽然上面这种循环中每次访问的开销很小但是还是有更加高效的做法,使用volatile关键字修饰stopRequested,volatile关键字可以保证任何一个线程在读取该域的时候都将看待最近刚刚被写入的值:
public class TestCode { private static volatile boolean stopRequested=false; public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(new Runnable() { public void run() { int i=0; while (!stopRequested) { i++; } } }); thread.start(); TimeUnit.SECONDS.sleep(1); stopRequested=true; } }
在使用volatile的时候要务必小心,例如:
private static volatile int nextNumber=1; public static int generateNumber(){ return nextNumber++; }
假如上述方法没有被同步是无法正常工作的,因为增量操作++不是原子性的,实际上++进行了两项操作:首先它读取值,然后写回一个新值,相当于在原来的值上再加上1。如果第二个线程在第一个线程读取旧值和写回新值之间读取这个域,第二个线程就会与第一个线程一起看到同一个值。这是安全性失败。虽然这种情况的发生时小概率事件但是还是需要我们注意的。改进的做法是在访问的方法上添加synchronized关键字,同时删去volatile来进行同步以确保多个调用不会交叉存取。其实对于这种情况最好的做法是使用AtomicLong来对generateNumber进行修饰。
总之,多线程访问共享可变数据的时候读和写数据的线程都必须进行同步,如果没有进行同步就无法保证一个线程的修改被另一个线程所感知,未能同步共享可变数据就会造成活性失败和安全性失败。如果只是线程之间的交互通信那么则不需要进行互斥,使用volatile关键字就可以搞定。
相关推荐
本篇文章是对同步访问共享的可变数据进行了详细的分析介绍,需要的朋友参考下
5. **线程同步**:当多个线程可能同时访问共享数据时,必须使用线程同步机制,如互斥量(Mutex)、信号量(Semaphore)或事件对象(Event),以防止数据竞争和不一致。 6. **导出和导入函数**:在DLL中,需要使用`...
这导致数据在各个节点间分散,使得传统的数据库链接(如Oracle的DBLink)无法直接用于数据共享,且复杂的数据关联操作变得困难。 在这样的背景下,数据共享主要有两种策略:数据服务化和数据同步冗余。数据服务化是...
由于医疗数据的校验、存储和同步一直是一个难点,因此医疗机构之间的数据共享变得困难。患者、医生和研究人员在访问和共享医疗数据时存在严格的限制,这一过程需要花费大量的资源和时间用于权限审核和数据校验。 ...
无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。 线程同步机制可以通过使用锁来实现。锁可以是对象锁、类锁或同步锁。锁的作用是防止多个线程同时访问同一个共享...
分布式文件系统是现代网络技术中不可或缺的一部分,它允许用户通过单一的访问点来访问网络中多台文件服务器上的数据。这种系统大大提高了数据管理的灵活性和数据的可用性,同时也为数据的负载均衡和数据冗余提供了...
在IT行业中,多数据源数据同步和数据接口是企业级应用开发中不可或缺的部分,尤其是在大数据时代,数据的整合、共享和实时更新变得至关重要。这里我们将深入探讨如何在Java Spring Boot框架下实现这些功能。 首先,...
3. **数据共享**:通过FTP协议,该工具使得不同系统之间的数据交换变得简单,无论是不同的操作系统还是不同的网络环境,只要支持FTP,就能实现数据共享。 4. **数据备份**:FTP数据同步工具支持数据备份功能,用户...
Vuex是Vue生态中的状态管理库,它提供了一个中心化的存储仓库,使得组件间的状态共享和管理变得更加有序和可控。 在这个"多頁面共享sessionStorage並同步至vuex範例"中,开发者可能使用了以下技术栈: 1. **Vuex**...
在多线程环境中,同步是指协调多个线程对共享资源的访问,避免数据竞争和不一致状态。在.NET中,有多种同步技术可供开发者使用,包括锁(Mutex, Monitor, Semaphore)、事件(EventWaitHandle)和条件变量(Monitor....
3. **Mutex对象同步多个对象**:Mutex是一种更强大的同步工具,它可以用来同步对多个对象的访问,防止多个线程同时访问共享资源。Mutex的WaitOne方法会让线程等待,直到获取到Mutex的所有权,ReleaseMutex则释放...
3. **只有共享变量(可变状态)才需要同步,常量或不可变对象可以并发访问。** 4. **同步可以应用于方法或代码块,根据需求选择合适的同步策略。** 5. **Java提供了`synchronized`关键字以及更高级的并发工具来实现...
综上所述,基于共享基础数据的信息系统集成方案是一条有效途径,它通过构建企业信息基础设施,解决了跨系统数据访问的难题,同时促进了企业信息化建设的深入发展。在实施过程中,需要注意整合遗留系统和新系统的平衡...
分布式系统中的数据共享策略通常要求能够支持大规模的数据访问,同时保证数据的及时性和准确性。 总的来说,RPC-DDSF框架的提出为分布式系统的开发提供了一种新的思路和工具,它能够帮助开发者快速构建可配置、可...
* asynchronized(异步的):不使用锁机制,允许多个线程同时访问共享资源。 * volatile(易变的):变量值可以被其他线程改变。 * atomic(原子的):操作不可被打断,能够保证数据的一致性。 * share(共享):多...
在IT行业中,文件同步是至关重要的任务,它允许用户在不同的设备或存储位置之间保持数据的一致性,确保重要文件的备份和访问便利。同步工具能够帮助我们自动检测并更新两个或多个目录之间的差异,使它们保持一致。 ...
传统上,非结构化数据管理系统如WinFS系统、Hadoop文件系统等,存在细粒度访问控制不足、元数据与内容维护不同步等问题,这些系统在数据安全性、共享性、类型多样性和管理性能等方面与实际需求存在一定差距。...
它们通常提供APIs,使得与其他系统集成和同步元数据变得更加便捷。 4. **自动化工具**:开发自动化工具或脚本,定期扫描和比对不同设备或系统的元数据,发现并修正不一致之处。这可以通过编程语言如Python或...