java多线程(并发编程)

为什么要使用java的并发编程

        过去的近30年间,计算机性能一直由摩尔定律来推动;从今天起,它将由Amdahl 定律推动。编写能够高效利用多处理器的代码,将会成为很大的挑战。
        “多核处理器正变得越来越便 宜”。现在看来,多处理器系统正变得越来越便宜这一趋势 还在继续,如果有什么不同,只是愈演愈烈了。几乎所有主要的计算机生产厂商都在初级 笔记本电脑和台式机中加入了多核处理器特性,而在服务器级别的机器上,每个处理器的 内核数量也多于去年的内核数量。事实上,寻找出单处理器的系统正变得越来越难了。
        这些硬件的发展趋势使软件的开发者面临着严峻的挑战。我们不能满足于仅仅在新的 CPU上运行现有的程序,使它们跑得更快;如果我们想要发挥全新的处理器的能力,就必 须编写程序来支持并发环境。在做这件事的过程中,会在架构、编程和测试方面遇到重大 的挑战。
现在,与以往任何时候相比,“并发”与每一位Java开发者都更加息息相关了
    随着计算机 技术的不断迅速发展,各种各样的编程模型也越来越多,越来越复杂化与多样化。虽然当 前CPU主频在不断升高,但是X86架构的硬件已经成为瓶颈,这种架构的CPU主频已经接近顶峰,多线程编程模型不仅是目前提 高应用性能的手段,更是下一代编程模型的核心思想。它的目的就是“最大限度地利用 CPU资源”,当某一线程的处理不需要占用CPU而只需要I/O等其他资源时,就可以让 需要占用CPU资源的其他线程有机会获得CPU资源。因此,就目前来说,多线程编程模 型仍是计算机系统架构的最有效的编程模型。

           我们已经进入了全新的时代,多核的时代。

线程的优点

摘自(java并发编程-1.2)

多核的影响是广泛且深入的。企业需要改变以往基于CPU数的计价方式。系统设计 者需要重新审视多核产生的并行性带来的影响。一线的开发人员要学习新的开发思路、技 巧和工具•并行的理念需要融入到系统的设计与实现的过程中。对程序员来说,多核带来 的变化并不像时钟频率增加那样透明。以前我们巳经对软件加入了很多的期望,比如可扩 展性、健壮性、可伸缩性、可测试性,等等,今天我们还要考虑软件是否充分发挥了微处 理器的全部性能。只有充分挖掘程序的并行性,才能让多核处理器物尽其用,才能让你的 软件在今后内核不断增加的日子里,得以保持升级。     

恰当地使用线程时,可以降低开发和维护的开销,并且能够提高复杂应用的性能。线 程通过把异步的工作流程转化为普遍存在的顺序流程,使程序模拟人类工作和交互变得更 容易了。另一方面,它们可以把复杂、难以理解的代码转化为直接、简洁的代码,这样更 容易读写及维护。
线程在GUI应用程序中是非常有用的,可用来改进用户接口的响应性,并且在服务器 应用中,用于提高资源的利用率和吞吐量。它们也可以简化JVM的实现——垃圾收集器 (garbage collector)通常运行于一个或多个持续工作的线程之间。大部分至关重要的Java 应用都依赖于线程,某种程度上是因为它们的组织结构需要这样。         

线程的风险(1.3)

线程安全的问题是微妙且出乎意料的,因为在没有进行充分同步的情况下,多线程中 的各个操作的顺序是不可预测的

活跃度的危险(1.3.2)

无限循环。。。

性能危险(1.3.3)

上下文切换等。。。

线程安全

无论何时,只要有多于一个的线程访问给定的状态变量,而且其中某个线程会写入该 变量,此时必须使用同步来协调线程对该变量的访问。Java中首要的同步机制是 synchronized关键字,它提供了独占锁。除此之外,术语“同步”还包括volatile变 量,显示锁和原子变量的使用。

你会想到在一些“特殊”情况下上述规则并不适用,不过你应该抵制住这种想法的诱 惑。程序如果忽略了必要的同步,可能看上去可以运行,而且能够通过测试,甚至能正常 地运行数年,但它仍然是存在隐患的,任何时刻都有可能崩溃。

共享对象(3)

        在没有同步的情况下,编译器,处理器,运行时安排操作的执行顺序可能安全出人意料。在没有进行适当同步的多线程程序中,尝试推断哪些 必然 发生在内存中的动作时,你总是会判断错误。

同步对可见性的保证(3.1)

        当访问一个共享的可变变量时,为什么要求所有线程由同一个锁进行同步,我们现在可以给出另一个里有----为了保证一个线程对数值进行的写入,其他线程也都可见。另一方面,如果一个线程在没有恰当的使用锁的情况下读取了变量,name这个变量很可能是一个过期的数据。(锁不仅仅是关于同步与互斥的,也是关于内存可见性的,为了保证所有线程都能够看到共享的、可变变量的最新值,读取和写入线程必须使用公共的锁进行同步。)

volatile变量(3.1.4)

java语言也提供了其他的选择,即一种同步的弱形式:volatile变量。它确保对一个变量的更新一可预见的方式告知其他的线程。当一个域声明为volatile类型后,编译器与运行时会监视这个变量;它是共享的,而且对它的操作不会与其他的内存操作一起被重排序。volatile变量不会缓存在寄存器或者缓存在对其他处理器隐藏的地方。所以读一个volatile类型的变量时,总会返回由某一线程写入的最新值。

所以从内存可见性的角度看,写入volatile变量就像退出同步块,读取volatile变量就像进入同步块。但是并不推荐国服依赖volatile变量所提供的可见性。依赖volatile变量来控制状态可见性的代码,比使用锁的代码更脆弱,更难理解。

volatile变量固然方便,但也存在限制。它们通常被当做标识完成、中断、状态的标记使用,尽管volatile也可以用来标示其他类型的状态信息,但是决定这样做之前请格外小心,比如volatile的语义不足以使自增操作(count++)原子化,除非你能保证只有一个线程对变量执行写操作。(原子变量提供了 读 改 写 原子操作的支持,而且常被用作“更优的volatile变量”)

加锁可以保证可见性与原子性;volatile变量只能保证可见性

只有满足了下面所有的标准后,你才能使用volatile变量;

  • 写入变量时并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值
  • 变量不需要与其他的状态变量共同参与不变约束
  • 而且,访问变量时,没有其他原因需要加锁。

发布和逸出(3.2)

java this 逸出_this引用逸出_QAQ平的博客-CSDN博客

线程封闭(3.3)

        访问共享的可变的数据要求使用同步。一个可以避免同步的方法就是不共享数据。如果数据仅在单线程中被访问,就不需要任何同步。线程封闭(thread confinement)技术是实现线程安全的最简单的方式之一。当对象封闭在一个线程中时,这种做法会自动成为线程安全的,即使被封闭的对象本身必能不是

         一种常见的使用线程限制的应用程序是应用池化的jdbc(java database connectivity)Connection对象。jdbc规范并没有要求connection对象时线程安全的。然而在典型的服务器应用中,线程总是从池中获得一个connection对象,并且用它处理一个单一的请求,最后把它归还。每个线程都会同步的处理大多数请求(比如servlet请求或者EJB调用),而且在connection对象在被归还前,池不会将它再分配给其他线程,因此这种连接管理模式隐式地将connection对象限制在处于请求处理期间的线程中。

正如语言并未提供强迫变量被锁保护的机制一样,语言也没有办法将对象限制在某一线程中。线程限制是你在程序设计中需要考虑的一个元素,它是在程序的实现中完成的。语言自身以及核心库提供了某些机制(本地变量和threadlocal类)有助于维护线程限制,尽管如此,程序员仍然要自己负责确保线程限制对象不会从它所在的线程中逸出。


未完待续。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值