`
406657836
  • 浏览: 4236 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

java必谈多线程

    博客分类:
  • java
阅读更多
程序语言作为开发软件的工具,与电脑沟通交流的工具。每个人都有选择工具的理由。我选择java的理由是:强规范,保证了很多低级错误,难以发觉的错误在编译期被检查;严格的内存管理,对内存的访问java是有严格的规范的,它可以防止数组下标越界,错误的内存访问;高性能的垃圾回收器,java在cms并发收集器出现后性能上了一个台阶,而且java虚拟机还在不断的发展进步,java的性能也会得到极大的提高,java的性能问题逐渐成了过去式;多线程,多线程是java优势所在,java语言在这方面也是下了很大的功夫,使java的多线程性能和安全性都如此强大。这些原因使我非常热爱在java语言上的学习,研究。

本文主要介绍java多线程方面的知识。正如很多java程序员知道的那样,java多线程确实涉及到很多注意事项。这篇博文主要是引出一些话题,对他们进行讨论。如果要深入讨论的话,每一个话题都足以用几篇博文来讲解。下面是将要出现的一些话题:

1,为什么要多线程(多线程的优势)

2,多线程有什么问题(多线程要解决的问题)

3,java对多线程的规范(java解决多线程问题对jvm作出的规范)

4,java解决多线程问题的手段,包括(synchronized,ReentrantLock,volatile,final,ThreadLocal,栈封闭,JUC技术等)


关于第一个话题:

要使用多线程的理由有很多,总体来说有如下(可能不全):

1,尽量利用系统资源,减少任务完成时间。(如,在IO阻塞的时候可以让出cpu,分布式运算 mapreduce)

2,多任务系统,有些事情需要并行执行。(如,需要响应用户中断请求)

3,需要同时为更多人提供服务,不能因为一个长任务完全占用系统资源,使一些短任务也不能服务。(如,web服务器)

4,一台服务器可以有很多cpu(单个cpu也可以支持超线程),所以多线程是必然的趋势。


关于第二个话题:

多线程下确实有很多不确定性。也很难像串行化执行那么调试程序。问题可能要一定的运行时间,一定的操作顺序才能产生。所以很多程序员在回避这个问题,很害怕去使用多线程。所以多线程要解决的第一个问题就是心理畏惧问题。对于技术上,多线程主要有两个问题要解决。这也是开发多线程程序时一定要思考的问题。

1,共享数据的可见性(一个线程写入的数据,何时对于其他线程可见)。

2,共享资源的竞争问题(多个线程同时请求一个资源,谁先谁后,如计数问题,转账问题等)。

注意这里都有共享二字,也就是需要在多线程中同时操作资源才可能出问题。下面讨论下这两个问题产生的原因和情景。

对于可见性问题:

cpu的执行速度快的惊人,以致于计算机执行速度的瓶颈在IO上。所以除了cpu寄存器缓存外,还有L1 ,L2——在cpu上的独立缓存,L3——同一个cpu槽内共享的缓存。然后才是主存,磁盘,网络等。在cpu需要访问数据时,会依次沿着上面的缓存读写数据。就拿写来说,假设一份数据在主存中,它会被一层层加载到寄存器缓存中来,假设cpu0要改变这份数据的值,会先写到寄存器缓存中,这时候数据并不会马上去修改主存中的数据,如果第二个cpu又来读这份数据,它不会里面读到之前的改变值而是读到一个"脏"值。也就是第一个操作对于第二个操作不可见。而且这时候第二个cpu可能根据条件判断,对这个值做出一些处理。由于不可见,会引发判断是失效,丢失的更新等等问题。不可见问题还有可能由重排序引起。

对于资源竞争问题:

资源竞争问题其实很好理解,如对一个变量计数。由于计数要分为读取,改变(依赖原来值做修改),替换三个步骤。如果多个线程不加任何限制的执行这个三个步骤,就会使其它步骤失效。还有HashMap扩容问题,打印机这些只能独占资源等等。这些都是资源竞争的一些问题。资源竞争问题远没有这么简单,特别是在高并发下,还可能引发一些硬件层面的问题。这个也是多线程的难点。资源竞争问题也可能由重排序引起。

关于第三个话题:

java对多线程提出来了自己的一套JMM模型。这个模型主要是对可见性约定——happens-before原则。happens-before有如下约定:


(1)同一个线程中的每条指令都happens-before于出现在其后的任何一个指令。

(2)对一个监视器的解锁happens-before于每一个后续对同一个监视器的加锁。

(3)对volatile字段的写入操作happens-before于后续这个字段的读操作。

(4)对于final修饰的变量,对它的构造happens-before于对它的第一次访问之前。

(5)Thread.start()的调用会happens-before于启动线程里面的动作。

(6)Thread中的所有动作都happens-before于其他线程检查到此线程结束或者Thread.join()中返回或者Thread.isAlive()==false。

(7)一个线程A调用另一个另一个线程B的interrupt()都happens-before于线程A发现B被A中断(B抛出异常或者A检测到B的isInterrupted()或者interrupted())。

(8)一个对象构造函数的结束happens-before与该对象的finalizer的开始

(9)如果A动作happens-before于B动作,而B动作happens-before与C动作,那么A动作happens-before于C动作

这些happens-before的约定解决了共享变量的可见性问题。对于共享资源竞争性主要是靠有锁的synchronized和lock,和无锁的cas操作保证。

关于第四个话题:

被final修饰的变量,是不可变对象(如果是一个引用类型,只是引用不可变,其值任然可变)。所以通过final修饰共享变量,可以大大减少多线程访问的复杂度。因为不可变对象一定是线程安全的。构造不可变对象是一个好的编程习惯。

栈封闭,其实就是说没有共享变量,把所有变量的分配都在本线程的方法栈内使用。不传递给其他线程使用。这其实是回避了多线程共享问题,很多时候我们仍然需要共享的。

ThreadLocal,这是另一个回避多线程共享变量的技术(只对本线程共享)。它把对象绑定到线程本地,Thread上的ThreadLocalMap中。这是一个弱键引用的map,键是ThreadLocal,value是具体本地线程共享的对象。所以这样的对象有两种方式被回收。第一ThreadLocal实例失去了强引用,在gc时可能会把它回收,第二这个线程失去了强引用,随着线程的回收而回收。所以ThreadLocal是不会内存溢出的。使用remove去移除不需要的变量是一种好习惯。如果线程长时间运行ThreadLocal通常也是不会失去强引用的,所以这里的内容得不到回收。

volatile变量主要是对可见性的约束,即它的写入总能立即被下一个读取的线程看到。但是它不保证原子操作。

synchronized是在对象或类上的内置锁。在synchronized作用域内的代码不能和区域外的代码重排序,并且读取共享变量能够看到它的最新状态,写入共享变量能够对持有这个锁的其它对象立即可见。

ReentrantLock提供了与synchronized相同的功能。它们的主要区别是

1,ReentrantLock必须自己释放锁。通常在finally释放。

2,ReentrantLock可以通过参数控制多线程访问的公平性。

3,ReentrantLock可以通过tryLock(),非阻塞的获得锁,也可以在指定等待时间内获得锁。synchronized一旦进入锁竞争就一定得等到锁,所以更容易产生死锁。

4,ReentrantLock可以响应中断,而synchronized是无法响应中断的。这一点很重要!一个好的线程设计都需要响应中断。

JUC的包很多主要是一些多线程工具。这里主要说下cas操作。像AtomicXXXX主要是利用cas操作,而不是锁。所以它的效率会高于有锁的同步。cas操作又主要是又cpu的硬件支持。JUC的内容很多在这里不单独讨论,有兴趣的同学可以看这篇博客,http://blog.csdn.net/xieyuooo/article/details/8594713


关于多线程的讨论暂时就到此了,如有任何纰漏还请多多指出,谢谢!
1
2
分享到:
评论
2 楼 406657836 2013-06-26  
502220545 写道
文章写的不错 学到了知识
有一点关于排版的建议:
  您是先列出了要讨论的问题。
  然后下面是针对每个问题做详细解答
  建议您能再做详细解答的时候重复一下问题描述而不是用对于第几个问题这样的字眼儿。
 

嗯 好的,以后多多注意。呵呵!
1 楼 502220545 2013-06-26  
文章写的不错 学到了知识
有一点关于排版的建议:
  您是先列出了要讨论的问题。
  然后下面是针对每个问题做详细解答
  建议您能再做详细解答的时候重复一下问题描述而不是用对于第几个问题这样的字眼儿。
 

相关推荐

    浅谈JAVA语言的多线程技术.pdf

    浅谈JAVA语言的多线程技术 一、多线程技术的概述 JAVA语言作为一种面向对象的编程语言,它具有平台独立性、安全性、网络化、多线程、面向对象等特点。其线程机制在实践中广泛应用而受到编程者的极大关心。本文就...

    浅谈JAVA中多线程的实现.zip

    在Java编程语言中,多线程是程序设计中的一个重要概念,尤其在开发高效能、响应迅速的应用时。本文将深入探讨Java中多线程的实现,帮助开发者理解如何利用这一特性来优化应用程序。 多线程是指在一个程序中同时运行...

    浅谈java多线程编程

    【Java多线程编程】是Java开发中不可或缺的一部分,它允许程序同时执行多个任务,从而提高效率和响应速度。本文将深入探讨Java多线程的优缺点、创建方式以及线程安全与同步机制。 **一、多线程的优缺点** 1. **...

    浅谈Java的多线程机制.pdf

    尤其在Java语言中,多线程机制不仅提升了应用程序的性能,而且还增强了程序对实时任务的控制能力。本文旨在探讨Java多线程机制的细节,并且深入解析其在提升程序性能方面的优势与实现方法。 ### 多线程编程的重要性...

    浅谈Java多线程编程.pdf

    "浅谈Java多线程编程" 从标题和描述可以看出,这篇文章的主题是讨论Java多线程编程的相关知识点。 多线程编程的概念 Java语言的一个重要特点是支持多线程机制,这使得Java程序可以支持多程序并发执行,从而提高...

    java中spring里实现多线程

    当我们谈到在Spring中实现多线程,实际上是在讨论如何在Spring环境中创建、管理和协调并发执行的任务。这涉及到Java的并发API以及Spring对这些API的包装和扩展。 首先,让我们了解Java中的多线程基础。在Java中,...

    Java多线程编程经验谈

    Java多线程编程是Java开发中的重要组成部分,尤其对于大型应用程序和并发性能要求较高的系统而言。虽然Java在多线程方面可能不如C++灵活,但Java提供了强大的平台无关性和自动内存管理,使得开发者可以专注于并发...

    浅谈JAVA中多线程的实现.pdf

    在Java开发中,多线程技术是一项重要的编程技能,它允许同时运行两个或多个部分,这些部分称为线程,每个线程可以处理不同的任务。这不仅能够提高程序的执行效率,还能改善用户体验,因为多线程可以实现程序的异步...

    Java 多线程编程入门到精通源代码.zip

    内含 chapter02-chapter18 共 17 个实例性源码项目,内容循序渐进,由入门到精通。尤其适合于没有 Java 线程开发经验的朋友。自己动手敲出本资源解压缩后的 ...相信你理解了此源码之后,即可步入 Java 多线程开发。

    浅谈多线程_让程序更高效的运行

    在Java中,多线程是通过创建并运行多个线程来实现的,每个线程代表着进程中的一条独立控制流。Java线程是抢占式的,意味着线程的执行是由操作系统调度,根据优先级和当前状态决定。 【进程】是一个程序或应用的实例...

    java多线程编程总结.pdf

    Java多线程编程是Java语言中的一项高级特性,它允许同时运行多个线程来执行多个任务,以达到提高程序运行效率和用户体验的目的。Java 5 是在Java多线程编程中具有重要意义的一个版本,因为它对Java的并发API进行了...

    浅谈java多线程wait,notify

    _java多线程wait、notify机制详解_ 在Java多线程编程中,wait和notify是两个非常重要的机制,用于实现线程之间的通信和同步。在本文中,我们将通过示例代码详细介绍Java多线程wait和notify的使用,帮助读者更好地...

    浅谈java多线程 join方法以及优先级方法

    在Java编程语言中,多线程是实现并发执行任务的重要机制。多线程允许程序同时执行多个独立的任务,从而提高程序的效率和响应性。本文将深入探讨Java中的`join()`方法以及线程的优先级概念。 首先,我们来看`join()`...

    浅谈Java多线程处理中Future的妙用(附源码)

    "浅谈Java多线程处理中Future的妙用" 在Java多线程处理中,Future是一个非常重要的概念,它可以帮助我们更好地处理并发任务。Future是一个未来对象,里面保存着线程处理结果,它像一个提货凭证,拿着它你可以随时去...

    来吧!再谈多线程(详细).doc

    了解了这些基础概念后,我们还可以深入研究更多 Java 多线程的高级特性,如 CountDownLatch、CyclicBarrier、Semaphore 和 ExecutorService 等工具类,它们能帮助我们更好地管理和协调线程,实现更复杂的并发控制...

    浅谈Java获得多线程的返回结果方式(3种)

    Java 多线程返回结果方式详解 在 Java 中,获取多线程的返回结果是一件复杂的事情。今天,我们将介绍三种方式来获取多线程的返回结果。 第一种方法:使用 Runnable 实现类 在这个方法中,我们可以在 Runnable 的...

    浅谈java中异步多线程超时导致的服务异常

    在Java编程中,异步多线程是一种常见的优化性能的方式,尤其在处理高并发场景时。这种方式通过将任务分配到不同的线程上,使得多个任务可以并行执行,从而提高程序的运行效率。然而,如果不正确地管理和控制线程,...

    浅谈Java多线程实现及同步互斥通讯

    浅谈Java多线程实现及同步互斥通讯 多线程实现方式: Java中的多线程实现方式共有两种:通过继承Thread类和通过实现Runnable接口。下面我们来详细了解这两种方式: 1. 通过继承Thread类来实现多线程: 通过继承...

Global site tag (gtag.js) - Google Analytics