C#和Java之比较(并发同步概述)

计算机的高速发展,在多核技术上要远远快于提升单核的计算能力。因而设计并发的程序成为提高软件性能的一大利器。

并发的程序虽然可以有效利用硬件资源,但同时也会增加程序设计的难度,其首要解决的就是同步的问题。

同步问题归纳而言就是要解决两个问题:活性失败(liveness failure)和 安全性失败(safety failture)。

  • 活性失败是指,线程A操作的变量c,在线程B中要访问的时候,不是最新的线程A操作赋值后的值。产生此类问题的原因在于现代CPU多采用了高速缓存,高速缓存变成了CPU和内存的中间桥梁,数据的过渡器,而CPU对高速缓存中的数据的修改并不会第一时间刷新到公用的内存中;多个线程运行在不同的CPU的情况下,就有可能出现读取的数据的不新鲜,导致活性失败。
  • 安全性失败,举例来说,线程A在调用某个计算方法, 运算过程处于中间状态时,有参与运算的变量被其他线程修改了值,导致了线程A的这次运算结果错误。这里的问题在于,线程A的这次运算不是一个原子操作,无法保证在运算的整体过程中数据的可控性。此类问题被称作安全性失败。

解决的办法归纳起来也是两大类

  1. 程序设计时,尽量减少跨线程的数据交互,尽量设计可重入的计算方法。
  2. 使用各种编程语言提供的同步机制,保证数据在多个线程之间的正确同步。

对于第一点来说,无论你是用哪种语言,都是一样的。

那么,针对第二点,让我们来看一下C#和Java在处理同步上的一些大同小异。

解决活性失败,C#和Java都提供了volatile这个关键字来修饰变量。这个关键字可以让程序运行时对被修饰的变量无条件的在高速缓存和主内存中实现数据同步。使用这个关键字可以解决数据不新鲜的问题,但是切记不可乱用,因为它会带来额外的性能开销,让高速缓存变得没有意义。

解决活性失败,当然也可以使用各种同步机制,这些同步机制也可以让需要在一起完成的操作不被其他线程打扰,成为原子操作,从而解决安全性失败问题。

同步大体来说可以分为两种

  • 互斥同步。互斥同步是指,线程A在访问某个竞争资源的时候,其他线程不能访问这个资源而被阻塞。这种方案带来的问题是比较大的性能开销用于线程阻塞和唤醒。这种同步机制其实是一种悲观的同步方案,在操作开始前就假设会有其他线程来抢资源而上锁了。
  • 非阻塞同步。这种同步机制是借助了操作和冲突检测的硬件指令实现的原子操作,实现的乐观同步机制。通俗的说,就是先进行操作,如果没有其他线程在征用共享数据,那操作就成功了,如果产生了冲突,那就不断重试,直到资源被释放。非阻塞同步不会让线程挂起,不需要被唤醒,所以如果在共享资源被短期暂用的情况下,比互斥(阻塞)同步拥有更好的性能。

在C#和Java中,比较典型的非阻塞同步机制就是自旋锁。

而同步机制的实现机制则是五花八门。

由于C#主要应用的平台在于windows,所以基本上它的同步机制都是基于windows的一些同步原语,包括事件,互斥锁,信号量,监视器;当然也有优化后的读写锁,瘦锁等等。

Java由于是跨平台的,所以提供的同步机制都需要jvm支持。可供选择的同步机制和封装有synchronized, ReentrantLock,CountDownLatch, CyclicBarrier, DelayQueue, PriorityBlockngQueue, ScheduledExecutor, Semaphore, Exchanger.

后续我们单独对每种实现进行相应的比较。

时间: 2024-12-12 08:22:52

C#和Java之比较(并发同步概述)的相关文章

Effective java 第十章 并发 同步访问共享的可变数据 读书笔记

并发 66.同步访问共享的可变数据 关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法,或者某一个代码块. 如果没有同步,一个线程的变化就不能被其他线程看到.同步不仅可以阻止一个线程看到对象处于不一致的状态之中,它还可以保证进入同步方法或者同步代码块的每个线程,都看到由一个锁保护的之前所有的修改效果. java语言规范保证读写一个变量是原子的,除非这个变量的类型为long或者double.意味着读取一个非long或者double类型的变量,可以保证返回的值是某个线程

java多线程、并发系列之 (synchronized)同步与加锁机制

Synchronized Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁定对象.在对象上锁定或在对象上同步. 当程序运行到synchronized同步方法或代码块时才该对象锁才起作用. 一个对象只有一个锁.所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁.这也意味着任何其他线程都不能进入该对象上的synchronized方法

《深入理解java虚拟机-高效并发》读书笔记

Java内存模型与线程 概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能,多任务运行是压榨手段,就如windows一样,我们使劲的压榨它运行多个任务,俱要high又要耍.并发则是另外一种更具体的应用场景.每秒事物处理数(Transactions per Second,tps)是最重要的指标.开发人员应该了解与运用并发. 硬件的效率与一致性 除了有软件上的并发,物理计算机也有并发问题.计算机的存储设备与处理器运算速度有几个数量级的差距,现代计算机都不得不加入一层高速缓存来作为内存与处理

EFFECTIVE JAVA 第十章 并发

EFFECTIVE  JAVA  第十章  并发 66.同步访问共享的可变数据 *java语言规范保证读或写一个变量是原子的(可以保证返回的值是某个线程保存在该变量中的),除非这个变量的类型为long或double.(但并不保证一个线程写入的值对于另一个线程是可见) *synchronized修饰方法.synchronized代码块可以实现同步 *volatile修饰的变量只保证读取的是主存里最新的值而不是内存中该值的拷贝,使用volatile变量必须遵循(即变量真正独立于其他变量和自己以前的值

数据量下高并发同步的讲解(不看,保证你后悔

4.常见的提高高并发下访问的效率的手段 首先要了解高并发的的瓶颈在哪里? 1.可能是服务器网络带宽不够 2.可能web线程连接数不够 3.可能数据库连接查询上不去. 根据不同的情况,解决思路也不同. 像第一种情况可以增加网络带宽,DNS域名解析分发多台服务器. 负载均衡,前置代理服务器nginx.apache等等 数据库查询优化,读写分离,分表等等 最后复制一些在高并发下面需要常常需要处理的内容: 尽量使用缓存,包括用户缓存,信息缓存等,多花点内存来做缓存,可以大量减少与数据库的交互,提高性能.

Java基础】并发 - 多线程

Java基础]并发 - 多线程 分类: Java2014-05-03 23:56 275人阅读 评论(0) 收藏 举报 Java 目录(?)[+] 介绍 Java多线程 多线程任务执行 大多数并发应用程序时围绕执行任务(task)进行管理的:所谓任务就是抽象的,离散的工作单元. 围绕执行任务来管理应用程序时,第一步是要指明一个清晰的任务边界.大多数应用服务器程序都选择了下面这个自然的任务辩解:单独的客户请求: 任务时逻辑上的单元: 任务 Runnable 表示一个任务单元(java.lang)

大数据量下高并发同步的讲解

对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了.而并发问题是绝大部分的程序员头疼的问题, 但话又说回来了,既然逃避不掉,那我们就坦然面对吧~今天就让我们一起来研究一下常见的并发和同步吧. 为了更好的理解并发和同步,我们需要先明白两个重要的概念:同步和异步    1.同步和异步的区别和联系         所谓同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是出于阻塞的,只有接收到 返回的值或消息后才往下执行其它的命令. 异步,

JAVA多线程和并发基础面试问答【转】

JAVA多线程和并发基础面试问答 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题.(校对注:非常赞同这个观点) Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含了不同的类和程序的单 一进程.线程可以被称为轻量

Java多线程与并发---学习总结(很详细)

Java多线程与并发---学习总结(很详细) 1.      计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓存一致性:多处理器系统中,因为共享同一主内存,当多个处理器的运算任务都设计到同一块内存区域时,将可能导致各自的缓存数据不一致的情况,则同步回主内存时需要遵循一些协议. 乱序执行优化:为了使得处理器内部的运算单位能尽量被充分利用. 2.      JAVA