- 浏览: 317845 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (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 991一直以来的多线程 ... -
Java多线程基础总结八:ReentrantReadWriteLock
2012-10-29 14:23 870说到ReentrantReadWriteLock,首先 ... -
Java多线程基础总结七:ReentrantLock
2012-10-29 13:56 874之前总结了部分无锁机制的多线程基础,理想的状态当然是利用 ... -
Java多线程基础总结六:synchronized(2)
2012-10-27 22:36 812早在总结一时,我就尽量的把synchronized的重 ... -
Java多线程基础总结五:atomic
2012-10-26 17:41 867在简单介绍java.util.concurrent.a ... -
Java多线程基础总结四:ThreadLocal
2012-10-22 11:34 791说到ThreadLocal,首先说说这个类的命名。直观上 ... -
Java多线程基础总结三: volatile
2012-10-22 11:34 817前面的两篇总结简单 ... -
Java多线程基础总结二: Thread
2012-10-22 11:34 913对于Thread来说只想说两 ... -
Java多线程基础总结一: synchronized
2012-10-21 14:21 779最近写关于并发的小应用,才发现真的该好好的正视jav ... -
Java多线程发展简史(4)
2012-09-25 14:00 921JDK 6.0 JDK 6.0对锁做了一些优化,比如锁自旋、 ... -
Java多线程发展简史(3)
2012-09-25 11:47 914JDK 1.4 在2002年4月发布 ... -
Java多线程发展简史(1)
2012-09-24 16:31 703引言 首先问这样一个 ... -
Java 多线程的同步示例及对象锁机制
2012-09-22 16:49 1316java多线程的同步依靠的是对象锁机制,synchronize ... -
Java ThreadLocal解决线程安全问题
2012-08-29 18:37 4244ThreadLocal是什么 早在JDK 1.2的版本中 ...
相关推荐
狂神说Java-多线程课程全部代码.rar
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用户界面组件 第...
1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 2.1 安装Java开发工具箱 2.1.1 下载JDK 2.1.2 设置执行路径 2.1.3 安装库源文件和文档 2.1.4 安装本书中的示例 2.1.5 导航Java目录 2.2 选择开发...
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发展简史 12 JAVA为什么能够流行? 13 JAVA各版本的含义 13 JAVA技术体系架构 14 JAVA的特性和优势 14 JAVA应用程序的运行机制 15 JVM(JAVA VIRTUAL MACHINE) 16 Java运行时环境JRE(Java Runtime Environment) ...
1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5导航Java目录 ...
1.1 Java语言发展简史2 1.2 认识Java语言3 1.2.1 Java语言特性3 1.2.2 JavaApplet4 1.2.3 丰富的类库4 1.2.4 Java的竞争对手5 1.2.5 Java在应用领域的优势7 1.3 Java平台的体系结构7 1.3.1 JavaSE标准版8 1.3.2 ...
第2章 线程安全性 2.1 什么是线程安全性 2.2 原子性 2.2.1 竞态条件 2.2.2 示例:延迟初始化中的竞态条件 2.2.3 复合操作 2.3 加锁机制 2.3.1 内置锁 2.3.2 重入 2.4 用锁来保护状态 2.5 活跃性与性能 第...
1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5导航Java目录 ...
1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6 1.3.2 Java程序的...
1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5导航Java目录 ...
面向对象语言的发展简史 26 内容总结 29 独立实践 30 第三章:面向对象的程序设计 31 学习目标 31 类和对象的描述 32 声明类 32 声明属性 33 声明成员方法 34 源文件的布局 36 包的声明 36 包与目录的布局 38 内容...
1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5导航Java目录 2.2选择...
1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5导航Java目录 ...
1. 4 Java发展简史 1.5关于Java的常见误解 第2章Java程序设计环境 2.1安装Java开发工具箱 2.1.1下载JDK 2.1.2设置执行路径 2.1.3安装库源代码和文档 2.1.4安装本书中的示例 2.1.5导航Java目录 ...