- 浏览: 327837 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (262)
- Java (20)
- 设计模式 (16)
- Oracle (13)
- Struts (1)
- 问题解决 (9)
- ibatis (2)
- Maven (5)
- Git (2)
- 实现原理 (6)
- 敏捷开发 (22)
- Spring (4)
- 算法 (8)
- MySQL (2)
- Java工具箱 (17)
- jQuery (1)
- 英语学习 (8)
- 杂谈 (15)
- 多线程 (15)
- Java解惑 (7)
- Linux (1)
- 重构36计 (6)
- 网络 (4)
- PHP (1)
- Socket (6)
- 面试 (1)
- JVM (14)
- 历史与故事 (5)
- 报表 (4)
- CMS (3)
- Windows (1)
- nginx (5)
- 架构设计 (7)
- RubyOnRails (2)
- Hadoop (8)
- Go (7)
- JS (1)
- Web (1)
- 项目实例 (5)
- ubuntu (4)
最新评论
-
jacking124:
按照你这个配置以后提示这个异常?Exception occur ...
Go语言学习:开发环境搭建及Hello World -
焦志广:
有请看http://jiaozhiguang-126-com. ...
Hadoop白皮书(1):分布式文件系统HDFS简介 -
w156445045:
Hadoop 有没windows环境下的配置呢,
谢谢。非常感 ...
Hadoop白皮书(1):分布式文件系统HDFS简介 -
xiangxm:
学习了。
Java 解惑知多少六 -
焦志广:
xhh_lite 写道怎么少了一个类?恩?不少啊,少那个类啊; ...
易学设计模式四 命令模式(Commond)
JDK 1.2
1998年年底的JDK1.2版本正式把Java划分为J2EE/J2SE/J2ME三个不同方向。在这个版本中,Java试图用Swing修正在 AWT中犯的错误,例如使用了太多的同步。可惜的是,Java本身决定了AWT还是Swing性能和响应都难以令人满意,这也是Java桌面应用难以比及其服务端应用的一个原因,在IBM后来的SWT,也不足以令人满意,JDK在这方面到JDK 1.2后似乎反省了自己,停下脚步了。值得注意的是,JDK高版本修复低版本问题的时候,通常遵循这样的原则:
向下兼容。所以往往能看到很多重新设计的新增的包和类,还能看到deprecated的类和方法,但是它们并不能轻易被删除。
严格遵循JLS(Java Language Specification),并把通过的新JSR(Java Specification Request)补充到JLS中,因此这个文档本身也是向下兼容的,后面的版本只能进一步说明和特性增强,对于一些最初扩展性比较差的设计,也会无能为力。这个在下文中关于ReentrantLock的介绍中也可以看到。
在这个版本中,正式废除了这样三个方法:stop()、suspend()和resume()。下面我就来介绍一下,为什么它们要被废除:
从上面的代码你应该可以看出两件事情:
使用stop来终止一个线程是不讲道理、极其残暴的,不论目标线程在执行任何语句,一律强行终止线程,最终将导致一些残缺的对象和不可预期的问题产生。
被终止的线程没有任何异常抛出,你在线程终止后找不到任何被终止时执行的代码行,或者是堆栈信息(上面代码打印的异常仅仅是main线程执行stop语句的异常而已,并非被终止的线程)。
很难想象这样的设计出自一个连指针都被废掉的类型安全的编程语言,对不对?再来看看suspend的使用,有引起死锁的隐患:
从上面的代码可以看出,Suspend线程被挂起时,依然占有锁,而当main线程期望去获取该线程来唤醒它时,彻底瘫痪了。由于suspend在这里是无期限限制的,这会变成一个彻彻底底的死锁。
相反,看看这三个方法的改进品和替代品:wait()、notify()和sleep(),它们令线程之间的交互就友好得多:
在wait和notify搭配使用的过程中,注意需要把它们锁定到同一个资源上(例如对象a),即:
一个线程中synchronized(a),并在同步块中执行a.wait()
另一个线程中synchronized(a),并在同步块中执行a.notify()
再来看一看sleep方法的使用,回答下面两个问题:
和wait比较一下,为什么sleep被设计为Thread的一个静态方法(即只让当前线程sleep)?
为什么sleep必须要传入一个时间参数,而不允许不限期地sleep?
如果我前面说的你都理解了,你应该能回答这两个问题。
在这个JDK版本中,引入线程变量ThreadLocal这个类:
每一个线程都挂载了一个ThreadLocalMap。ThreadLocal这个类的使用很有意思,get方法没有key传入,原因就在于这个 key就是当前你使用的这个ThreadLocal它自己。ThreadLocal的对象生命周期可以伴随着整个线程的生命周期。因此,倘若在线程变量里存放持续增长的对象(最常见是一个不受良好管理的map),很容易导致内存泄露。
上面的例子会一直打印var1,而不会打印var2,就是因为不同线程中的ThreadLocal是互相独立的。
ref:http://developer.51cto.com/art/201209/357617_1.htm
1998年年底的JDK1.2版本正式把Java划分为J2EE/J2SE/J2ME三个不同方向。在这个版本中,Java试图用Swing修正在 AWT中犯的错误,例如使用了太多的同步。可惜的是,Java本身决定了AWT还是Swing性能和响应都难以令人满意,这也是Java桌面应用难以比及其服务端应用的一个原因,在IBM后来的SWT,也不足以令人满意,JDK在这方面到JDK 1.2后似乎反省了自己,停下脚步了。值得注意的是,JDK高版本修复低版本问题的时候,通常遵循这样的原则:
向下兼容。所以往往能看到很多重新设计的新增的包和类,还能看到deprecated的类和方法,但是它们并不能轻易被删除。
严格遵循JLS(Java Language Specification),并把通过的新JSR(Java Specification Request)补充到JLS中,因此这个文档本身也是向下兼容的,后面的版本只能进一步说明和特性增强,对于一些最初扩展性比较差的设计,也会无能为力。这个在下文中关于ReentrantLock的介绍中也可以看到。
在这个版本中,正式废除了这样三个方法:stop()、suspend()和resume()。下面我就来介绍一下,为什么它们要被废除:
package com.jiaozg.thread; public class Stop extends Thread { @Override public void run() { try { while (true) ; } catch (Throwable e) { e.printStackTrace(); } } public static void main(String[] args) { Thread thread = new Stop(); thread.start(); try { sleep(1000); } catch (InterruptedException e) { } thread.stop(new Exception("stop")); // note the stack trace } }
从上面的代码你应该可以看出两件事情:
使用stop来终止一个线程是不讲道理、极其残暴的,不论目标线程在执行任何语句,一律强行终止线程,最终将导致一些残缺的对象和不可预期的问题产生。
被终止的线程没有任何异常抛出,你在线程终止后找不到任何被终止时执行的代码行,或者是堆栈信息(上面代码打印的异常仅仅是main线程执行stop语句的异常而已,并非被终止的线程)。
很难想象这样的设计出自一个连指针都被废掉的类型安全的编程语言,对不对?再来看看suspend的使用,有引起死锁的隐患:
package com.jiaozg.thread; public class Suspend extends Thread { @Override public void run() { synchronized (this) { while (true) ; } } public static void main(String[] args) { Thread thread = new Suspend(); thread.start(); try { sleep(1000); } catch (InterruptedException e) { } thread.suspend(); synchronized (thread) { // dead lock System.out.println("got the lock"); thread.resume(); } } }
从上面的代码可以看出,Suspend线程被挂起时,依然占有锁,而当main线程期望去获取该线程来唤醒它时,彻底瘫痪了。由于suspend在这里是无期限限制的,这会变成一个彻彻底底的死锁。
相反,看看这三个方法的改进品和替代品:wait()、notify()和sleep(),它们令线程之间的交互就友好得多:
package com.jiaozg.thread; public class Wait extends Thread { @Override public void run() { System.out.println("start"); synchronized (this) { // wait/notify/notifyAll use the same // synchronization resource try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); // notify won't throw exception } } } public static void main(String[] args) { Thread thread = new Wait(); thread.start(); try { sleep(2000); } catch (InterruptedException e) { } synchronized (thread) { System.out.println("Wait() will release the lock!"); thread.notify(); } } }
在wait和notify搭配使用的过程中,注意需要把它们锁定到同一个资源上(例如对象a),即:
一个线程中synchronized(a),并在同步块中执行a.wait()
另一个线程中synchronized(a),并在同步块中执行a.notify()
再来看一看sleep方法的使用,回答下面两个问题:
和wait比较一下,为什么sleep被设计为Thread的一个静态方法(即只让当前线程sleep)?
为什么sleep必须要传入一个时间参数,而不允许不限期地sleep?
如果我前面说的你都理解了,你应该能回答这两个问题。
package com.jiaozg.thread; public class Sleep extends Thread { @Override public void run() { System.out.println("start"); synchronized (this) { // sleep() can use (or not) any synchronization resource try { /** * Do you know: <br> * 1. Why sleep() is designed as a static method comparing with * wait?<br> * 2. Why sleep() must have a timeout parameter? */ this.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); // notify won't throw exception } } } public static void main(String[] args) { Thread thread = new Sleep(); thread.start(); try { sleep(2000); } catch (InterruptedException e) { } synchronized (thread) { System.out.println("Has sleep() released the lock!"); thread.notify(); } } }
在这个JDK版本中,引入线程变量ThreadLocal这个类:
每一个线程都挂载了一个ThreadLocalMap。ThreadLocal这个类的使用很有意思,get方法没有key传入,原因就在于这个 key就是当前你使用的这个ThreadLocal它自己。ThreadLocal的对象生命周期可以伴随着整个线程的生命周期。因此,倘若在线程变量里存放持续增长的对象(最常见是一个不受良好管理的map),很容易导致内存泄露。
package com.jiaozg.thread; public class ThreadLocalUsage extends Thread{ public User user = new User(); public User getUser() { return user; } @Override public void run() { this.user.set("var1"); while (true) { try { sleep(1000); } catch (InterruptedException e) { } System.out.println(this.user.get()); } } public static void main(String[] args) { ThreadLocalUsage thread = new ThreadLocalUsage(); thread.start(); try { sleep(4000); } catch (InterruptedException e) { } thread.user.set("var2"); } }
package com.jiaozg.thread; public class User { private static ThreadLocal<Object> enclosure = new ThreadLocal<Object>(); // is it must be static? public void set(Object object) { enclosure.set(object); } public Object get() { return enclosure.get(); } }
上面的例子会一直打印var1,而不会打印var2,就是因为不同线程中的ThreadLocal是互相独立的。
ref:http://developer.51cto.com/art/201209/357617_1.htm
发表评论
-
Java多线程基础总结九:Mina窥探
2012-10-29 14:54 1017一直以来的多线程 ... -
Java多线程基础总结八:ReentrantReadWriteLock
2012-10-29 14:23 899说到ReentrantReadWriteLock,首先 ... -
Java多线程基础总结七:ReentrantLock
2012-10-29 13:56 909之前总结了部分无锁机制的多线程基础,理想的状态当然是利用 ... -
Java多线程基础总结六:synchronized(2)
2012-10-27 22:36 839早在总结一时,我就尽量的把synchronized的重 ... -
Java多线程基础总结五:atomic
2012-10-26 17:41 906在简单介绍java.util.concurrent.a ... -
Java多线程基础总结四:ThreadLocal
2012-10-22 11:34 817说到ThreadLocal,首先说说这个类的命名。直观上 ... -
Java多线程基础总结三: volatile
2012-10-22 11:34 844前面的两篇总结简单 ... -
Java多线程基础总结二: Thread
2012-10-22 11:34 941对于Thread来说只想说两 ... -
Java多线程基础总结一: synchronized
2012-10-21 14:21 811最近写关于并发的小应用,才发现真的该好好的正视jav ... -
Java多线程发展简史(4)
2012-09-25 14:00 953JDK 6.0 JDK 6.0对锁做了一些优化,比如锁自旋、 ... -
Java多线程发展简史(3)
2012-09-25 11:47 936JDK 1.4 在2002年4月发布 ... -
Java多线程发展简史(1)
2012-09-24 16:31 739引言 首先问这样一个 ... -
Java 多线程的同步示例及对象锁机制
2012-09-22 16:49 1351java多线程的同步依靠的是对象锁机制,synchronize ... -
Java ThreadLocal解决线程安全问题
2012-08-29 18:37 4291ThreadLocal是什么 早在JDK 1.2的版本中 ...
相关推荐
《狂神说Java-多线程课程全部代码》是一个涵盖了Java多线程和并发编程的实战教程资源。这个压缩包包含了一系列的示例代码(如demo01),旨在帮助开发者深入理解和掌握Java中的多线程技术及其在并发环境中的应用。 ...
1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...
1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java 程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第...
Java是一种广泛使用的编程语言,以其平台独立性、面向对象的设计、简洁性、健壮性、安全性、解释性、多线程处理能力和动态特性著称。自1995年由Sun Microsystems公司发布以来,Java经历了多次重要更新,持续推动其...
1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...
1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...
1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...
Java是Sun公司开发的一种高级编程语言,具有跨平台、安全、面向对象、简单、高性能、分布式、多线程和健壮性等特性。Java的历史可以追溯到1991年,当时James Gosling率领的Sun公司工程师小组想要设计一种小型计算机...
Java的发展简史始于1991年,由SUN Microsystems公司的James Gosling、Bill Joe等人在开发名为Oak的软件时诞生。虽然最初目标并未成功,但 Oak 后来演变为Java,迅速获得了广泛的关注。Java因其特性被众多著名公司...
Java的发展简史表明,其名称来源于印度尼西亚的一个岛屿,同时又与程序员喜爱的咖啡相关。Java在互联网时代的成功主要归功于其跨平台特性,允许程序在不同操作系统上运行而无需重新编译。自1995年发布以来,Java已经...
Java的特性和优势包括自动内存管理(垃圾回收)、多线程支持、丰富的类库以及强大的异常处理机制,这些特性使得Java在各种应用场景中表现出色。 了解Java应用程序的运行机制至关重要。Java程序在运行时需要JRE...
1. **JAVA语言发展简史** - JAVA起初名为Oak,由Sun公司的Green Team小组创建,最初设计用于嵌入式系统。 - 1994年,随着互联网的兴起,Oak被重新定位并更名为JAVA,适应网络环境,因其在网络上的优势迅速获得广泛...
2. Java语言特性:Java是一门简单、面向对象、健壮、安全、解释执行、与平台无关、支持多线程和动态的编程语言。这些特性让Java成为开发企业级应用和移动应用的理想选择。 3. Java程序运行机制:Java程序通过Java...
#### I/O发展简史 - **JDK1.0-1.3**: 在此期间,Java的I/O模型主要依赖于传统的阻塞I/O方式,这种模式下,应用程序在等待I/O操作完成时无法执行其他任务,导致效率低下。此外,当时的Java在字符集编码支持、文本...
JAVA的发展简史可追溯到1995年,由Sun Microsystems推出,其设计理念是“一次编写,到处运行”。JAVA之所以流行,是因为它具有跨平台性、安全性和高性能,同时提供了丰富的类库。JAVA分为多个版本,如JDK(Java ...
- **多线程**:Java内置了对多线程的支持,可以轻松地开发出高性能的应用程序。 - **动态性**:Java具有高度动态性,可以通过反射机制在运行时获取类的信息,并通过动态代理等方式实现动态绑定。 - **体系结构中立...