- 浏览: 132393 次
- 性别:
- 来自: ...
文章分类
最新评论
最近写关于并发的小应用,才发现真的该好好的正视java的多线程了。之前没有深入的掌握,用起来也是那么的吃力。作为J2SE里面为数不多的重要难点之一,多线程应用一直是我以敬畏的心态去尽量避开的,只是通过一些实例掌握一些简单的应用。这段时间会多用点时间去掌握,有需要写下来的我也会通过这种方式既分享又加深理解。
首先这篇只涉及基础的知识整理,对于并发包java.util.concurrent内的线程池和锁我会看情况在之后的总结中写点东西。对于进程的概念我们都很熟悉,它是应用程序级的隔离,不同的应用程序之间的进程几乎不共享任何资源。而线程则可以说是应用程序内的隔离,一种相对低级别的隔离。一个进程可以有多个线程,它们之间隔离的内容大致包括:a.自身的堆栈,b.程序计数器,c.局部变量;共享应用的内容大致包括:a.内存,b.文件句柄,c.进程状态等。线程不是Java自身的概念,它是操作系统底层的概念。Java作为一种应用语言把线程的操作通过API提升到应用开发的支持,但是在并发性的支持上并不是那么美好。
Java在设计时,每个对象都有一个隐式的锁,这个锁的使用则是通过synchronized关键字来显式的使用。在JDK5.0以后引用了java.util.concurrent.ReentrantLock作为synchronized之外的选择,配和Condition可以以一种条件锁的机制来管理并发的线程,之后的总结再介绍。提到synchronized,多数的初学者都知道Object的wait(),notify(),notifyAll()是配和其使用的,但是为什么要在同步内才能用对象的这些方法呢(不然抛IllegalMonitorStateException)?
我想因为没有synchronized让对象的隐式锁发挥作用,那么方法或者方法块内的线程在同一时间可能存在多个,假设wait()可用,它会把这些线程统统的加到wait set中等待被唤醒,这样永远没有多余的线程去唤醒它们。每个对象管理调用其wait(),notify()的线程,使得别的对象即使想帮忙也帮不上忙。这样的结果就是多线程永远完成不了多任务,基于此Java在设计时使其必须与synchronized一起使用,这样获得隐式锁的线程同一时间只有一个,当此线程被对象的wait()扔到wait set中时,线程会释放这个对象的隐式锁等待被唤醒的机会,这样的设计会大大降低死锁。另外同一个对象隐式锁作用下的多个方法或者方法块在没有锁的限制下可以同时允许多个线程在不同的方法内wait和notify,严重的竞争条件使得死锁轻而易举。所以Java设计者试图通过Monitor Object模式解决这些问题,每个对象都是Monitor用于监视拥有其使用权的线程。
但是synchronized这种获得隐式锁的方式本身也是有隐患问题的:a.不能中断正在试图获得锁的线程,b.试图获得锁时不能设定超时,c.每个锁只有一个条件太少。对于最后一项的设计前面提到的JDK5的方案是可以弥补的,一个ReentrantLock可以有多个Condition,每个条件管理获得对象锁满足条件的线程,通过await(),signalAll()使只关于Condition自己放倒的线程继续运行,或者放倒一些线程,而不是全部唤醒等等。但对于前两者的极端情况会出现死锁。下面的这个例子:
假设场景:线程A调用methodOne(),获得lock1的隐式锁后,在获得lock2的隐式锁之前线程B进入运行,调用methodTwo(),抢先获得了lock2的隐式锁,此时线程A等着线程B交出lock2,线程B等着lock1进入方法块,死锁就这样被创造出来了。
以上的例子不直观的话,再看一个实例顺便看看wait()的缺陷:
上面的这个例子也会出现死锁,为什么呢?首先看WaitAndNotify这个类,在push和pop方法上有synchronized关键字,方法内部也有synchronized,那么当WaitAndNotify实例化时会有两个对象的隐式锁,一个是WaitAndNotify对象自身的,作用在方法上;另一个就是方法内部同步用到的list的。主线程开启两个线程t1和t2,t1进入pop方法此时list为空,它先后获得了wan和list的隐式锁,接着就被wait扔进wait set等待去了。注意这个wait()方法是谁的?答案是wan的,所以它释放了wan的隐式锁,但是把list的死死的抓着不放。此时t2终于得到了wan的隐式锁进入push方法,但是不幸的是list的隐式锁它这辈子也得不到了。。。
就是由于wait的设计是针对对象管理线程的,而又没有其他的可以类似栈的方式层层释放锁,导致死锁的杯具了。关于synchronized和wait(),notify(),notifyAll()的故事,我想我能瞎编的暂时这么多了,不然滔滔江水就又杯具了,哈哈。下面简单的讲讲java.lang.Thread的特色小故事。(待续...)
PS:"多线程基础总结六"算是本文的补遗了,呵呵。
首先这篇只涉及基础的知识整理,对于并发包java.util.concurrent内的线程池和锁我会看情况在之后的总结中写点东西。对于进程的概念我们都很熟悉,它是应用程序级的隔离,不同的应用程序之间的进程几乎不共享任何资源。而线程则可以说是应用程序内的隔离,一种相对低级别的隔离。一个进程可以有多个线程,它们之间隔离的内容大致包括:a.自身的堆栈,b.程序计数器,c.局部变量;共享应用的内容大致包括:a.内存,b.文件句柄,c.进程状态等。线程不是Java自身的概念,它是操作系统底层的概念。Java作为一种应用语言把线程的操作通过API提升到应用开发的支持,但是在并发性的支持上并不是那么美好。
Java在设计时,每个对象都有一个隐式的锁,这个锁的使用则是通过synchronized关键字来显式的使用。在JDK5.0以后引用了java.util.concurrent.ReentrantLock作为synchronized之外的选择,配和Condition可以以一种条件锁的机制来管理并发的线程,之后的总结再介绍。提到synchronized,多数的初学者都知道Object的wait(),notify(),notifyAll()是配和其使用的,但是为什么要在同步内才能用对象的这些方法呢(不然抛IllegalMonitorStateException)?
我想因为没有synchronized让对象的隐式锁发挥作用,那么方法或者方法块内的线程在同一时间可能存在多个,假设wait()可用,它会把这些线程统统的加到wait set中等待被唤醒,这样永远没有多余的线程去唤醒它们。每个对象管理调用其wait(),notify()的线程,使得别的对象即使想帮忙也帮不上忙。这样的结果就是多线程永远完成不了多任务,基于此Java在设计时使其必须与synchronized一起使用,这样获得隐式锁的线程同一时间只有一个,当此线程被对象的wait()扔到wait set中时,线程会释放这个对象的隐式锁等待被唤醒的机会,这样的设计会大大降低死锁。另外同一个对象隐式锁作用下的多个方法或者方法块在没有锁的限制下可以同时允许多个线程在不同的方法内wait和notify,严重的竞争条件使得死锁轻而易举。所以Java设计者试图通过Monitor Object模式解决这些问题,每个对象都是Monitor用于监视拥有其使用权的线程。
但是synchronized这种获得隐式锁的方式本身也是有隐患问题的:a.不能中断正在试图获得锁的线程,b.试图获得锁时不能设定超时,c.每个锁只有一个条件太少。对于最后一项的设计前面提到的JDK5的方案是可以弥补的,一个ReentrantLock可以有多个Condition,每个条件管理获得对象锁满足条件的线程,通过await(),signalAll()使只关于Condition自己放倒的线程继续运行,或者放倒一些线程,而不是全部唤醒等等。但对于前两者的极端情况会出现死锁。下面的这个例子:
class DeadLockSample{ public final Object lock1 = new Object(); public final Object lock2 = new Object(); public void methodOne(){ synchronized(lock1){ ... synchronized(lock2){...} } } public void methodTwo(){ synchronized(lock2){ ... synchronized(lock1){...} } } }
假设场景:线程A调用methodOne(),获得lock1的隐式锁后,在获得lock2的隐式锁之前线程B进入运行,调用methodTwo(),抢先获得了lock2的隐式锁,此时线程A等着线程B交出lock2,线程B等着lock1进入方法块,死锁就这样被创造出来了。
以上的例子不直观的话,再看一个实例顺便看看wait()的缺陷:
import java.util.LinkedList; import java.util.List; /** * User: yanxuxin * Date: Dec 9, 2009 * Time: 5:58:39 PM */ public class DeadLockSample { public static void main(String[] args) { final WaitAndNotify wan = new WaitAndNotify(); Thread t1 = new Thread(new Runnable(){ public void run() { wan.pop(); } }); Thread t2 = new Thread(new Runnable(){ public void run() { wan.push("a"); } }); t1.start(); t2.start(); } } class WaitAndNotify { final List<String> list = new LinkedList<String>(); public synchronized void push(String x) { synchronized(list) { list.add(x); notify(); } } public synchronized Object pop() { synchronized(list) { if(list.size() <= 0) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } return list.size(); } } }
上面的这个例子也会出现死锁,为什么呢?首先看WaitAndNotify这个类,在push和pop方法上有synchronized关键字,方法内部也有synchronized,那么当WaitAndNotify实例化时会有两个对象的隐式锁,一个是WaitAndNotify对象自身的,作用在方法上;另一个就是方法内部同步用到的list的。主线程开启两个线程t1和t2,t1进入pop方法此时list为空,它先后获得了wan和list的隐式锁,接着就被wait扔进wait set等待去了。注意这个wait()方法是谁的?答案是wan的,所以它释放了wan的隐式锁,但是把list的死死的抓着不放。此时t2终于得到了wan的隐式锁进入push方法,但是不幸的是list的隐式锁它这辈子也得不到了。。。
就是由于wait的设计是针对对象管理线程的,而又没有其他的可以类似栈的方式层层释放锁,导致死锁的杯具了。关于synchronized和wait(),notify(),notifyAll()的故事,我想我能瞎编的暂时这么多了,不然滔滔江水就又杯具了,哈哈。下面简单的讲讲java.lang.Thread的特色小故事。(待续...)
PS:"多线程基础总结六"算是本文的补遗了,呵呵。
发表评论
文章已被作者锁定,不允许评论。
-
一道位操作的趣味编程题
2010-03-14 10:50 2128看到一道很有意思的编程题:大厅里有64盏灯,每盏灯都编 ... -
一道字符串截取的编程题
2010-03-11 10:52 2324最近接触到一道字符串截取的编程题:编写一个截取字符串的 ... -
一道多线程趣味热身题
2010-02-28 18:01 1965保持对知识点或者技术的熟悉度对于程序员至关重要,要学会 ... -
疑似Google多线程面试题的Java实现
2010-02-24 17:39 4992来到一个完全陌生的地方,即将一切从新开始,内心兴奋又忐 ... -
Mina的线程池实现分析(2)
2010-02-10 17:31 4602分析了I/O事件的存储,下面看看多个Worker同时工 ... -
Mina的线程池实现分析(1)
2010-02-10 17:28 11644线程池是并发应用中,为了减少每个任务调用的开销增强性能 ... -
多线程基础总结十一--ConcurrentLinkedQueue
2010-02-03 17:52 12976ConcurrentLinkedQueue充分使用了a ... -
LinkedBlockingQueue应用--生产消费模型简单实现
2010-01-29 20:45 8238之前介绍时LinkedBlockingQueue提到了 ... -
多线程基础总结十--LinkedBlockingQueue
2010-01-28 14:33 15456随着多线程基础总结的增多,却明显的感觉知道的越来越少, ... -
号称放倒一片的一道J2SE基础题的个人理解
2010-01-23 14:07 2855近日无意中看到一道Java基础题,号称在接受测试的10 ... -
多线程基础总结九--Mina窥探(1)
2010-01-21 23:46 5470一直以来的多线程的基础总结都是脱离应用的,但是要说多线 ... -
多线程基础总结八--ReentrantReadWriteLock
2010-01-15 23:22 7568说到ReentrantReadWriteLock,首先 ... -
多线程基础总结七--ReentrantLock
2010-01-09 23:17 7741之前总结了部分无锁机制的多线程基础,理想的状态当然是利 ... -
关于atomic问题的一点理解
2009-12-30 16:42 2495之前看到一个帖子是关于atomic使用的,当时没有仔细 ... -
多线程基础总结六--synchronized(2)
2009-12-18 18:45 1920早在总结一时,我就尽量的把synchronized的重点 ... -
多线程基础总结五--atomic
2009-12-17 19:46 3602在简单介绍java.util.c ... -
多线程基础总结四--ThreadLocal
2009-12-16 19:48 2769说到ThreadLocal,首先 ... -
多线程基础总结三--volatile
2009-12-15 20:09 2605前面的两篇总结简 ... -
多线程基础总结二--Thread
2009-12-12 23:27 2717对于Thread来说 ... -
由destory-method引发的IOC容器设计的思考
2009-12-07 16:51 1733第一次读Spring的源 ...
相关推荐
#### 一、线程基础概念 **线程状态:** 在探讨多线程之前,我们需要了解线程的基本状态转换。一个典型的线程生命周期包括以下几个阶段: 1. **Start(启动):** 当线程被创建后调用`start()`方法时,线程处于启动...
在IT行业中,多线程是程序并发执行的一种方式,它极大地提高了系统资源的利用率和程序...在学习过程中,可以参考"多线程基础总结01.bmp"和"多线程基础总结01.mmap"等文件,它们可能提供了更为详细和直观的结构化知识。
在Java编程语言中,多线程是并发执行多个任务或操作的一种方式,这对于优化系统性能、提高资源利用率具有重要意义。...对于开发者来说,理解和熟练掌握`synchronized`是编写高效、安全的多线程Java程序的基础。
### 多线程基础 #### 1. 多线程概念 多线程是指在一个程序中包含多个控制流,它们可以并发执行不同的任务。在Java中,多线程的实现通常借助于`Thread`类或实现`Runnable`接口。多线程能够提高CPU的利用率,改善应用...
Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...
一、多线程基础知识 1. **线程定义**:线程是操作系统分配处理器时间的基本单位,一个进程可以包含一个或多个线程,每个线程都有自己独立的程序计数器、系统栈和局部变量,但共享同一块内存空间,包括全局变量和...
1. **线程基础**(IBM多线程教程一-线程基础.doc): - 线程的概念:线程是操作系统分配CPU时间的基本单元,一个进程中可以有多个线程同时执行。 - 创建线程:通过实现`Runnable`接口或继承`Thread`类来创建线程...
### Java多线程编程大总结 #### 一、Java多线程编程的演进与重要性 Java多线程编程自Java 5之后经历了显著的革新与扩展,引入了强大的并发包,极大地增强了多线程编程的能力。在Java 5之前,多线程的支持较为薄弱...
本篇总结涵盖了Java多线程的基础概念、创建与启动、线程调度、同步与协作以及新特性。 **一、Java线程:概念与原理** 1. **线程与进程**: - **进程**:是操作系统资源分配的基本单位,每个进程都有独立的内存...
### JAVA-基础多线程 #### 一、线程概念 1. **线程定义**: - 线程是程序执行时的一条路径,是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 - 一个线程指的是进程中一个...
以上内容涵盖了Java多线程的基础知识,包括创建、同步、终止、线程安全和并发控制等方面。通过实际的代码实践,可以深入理解并掌握这些概念,提升多线程编程的能力。同时,文档中的代码示例能帮助读者更好地理解和...
因此,在多线程环境下推荐使用`StringBuffer`,而在单线程环境中,`StringBuilder`通常更快,因为它没有同步开销。 对于`==`和`equals()`方法的使用,`==`用于比较两个对象是否指向内存中的同一个位置,即检查它们...
Java多线程编程基础 多线程编程是Java编程中一个非常重要的知识点,它可以使我们的程序更加高效、更加快速。今天,我们将要学习Java多线程编程的基础知识,包括多线程原理、线程状态、线程同步等内容。 一、多线程...
Java多线程编程是构建高性能、高并发应用程序的基础,涉及线程的创建、管理、同步、调度等多个方面。掌握线程生命周期、同步机制、并发工具和最佳实践是成为一名优秀Java开发者的关键。通过深入理解并熟练运用Java多...
1. **线程基础** - 线程是操作系统分配CPU时间的基本单位,一个进程可以包含一个或多个线程。 - Java中通过`java.lang.Thread`类或者实现`Runnable`接口来创建线程。 - 主线程:每个Java应用程序都有一个主线程,...
### Java多线程小结 ...但是,多线程编程也面临着诸如死锁、竞态条件等问题,因此需要开发者具备良好的设计思路和扎实的基础知识。掌握多线程的原理和实现机制对于编写高质量的Java应用至关重要。
在Java编程语言中,多线程是核心特性之一,它允许程序同时执行多个任务,从而提高了应用程序的效率和响应性。本节我们将深入探讨Java中的多线程概念,包括其重要性、创建方法以及相关机制。 一、多线程的重要性 1....
总结来说,Java基础多线程练习题主要涵盖了线程的创建、同步与通信、线程安全以及并发工具的使用。通过这些题目,你可以更好地理解线程的工作原理,学会在实际项目中有效利用多线程提高程序性能,避免潜在的问题。在...
总结起来,Java多线程和线程安全是构建高性能应用的基础,而在HTTP协议下实现断点续传则能显著提升大文件下载的体验。理解并熟练运用这些技术,可以让你在Java开发中游刃有余,提供更优质的服务。