`

Java多线程发展简史(2)

阅读更多
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()。下面我就来介绍一下,为什么它们要被废除:


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
  • 大小: 34.7 KB
分享到:
评论

相关推荐

    狂神说Java-多线程课程全部代码.rar

    狂神说Java-多线程课程全部代码.rar

    java核心技术第八版源代码(全)

    1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...

    [java.核心技术.第八版].Core.Java..8th.Edition源代码 示例代码

    1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java 程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第...

    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目录 2.2 选择开发...

    Java核心技术 卷I(原书第8版).part2 PDF

    1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...

    Java核心技术 卷I(原书第8版).Part1 pdf

    1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...

    Core Java. Volume I. Fundamentals, 8th Edition JAVA核心技术1基础知识

    1.4 Java发展简史 1.5 关于Java的常见误解 第2章 Java程序设计环境 第3章 Java基本的程序设计程序 第4章 对象与类 第5章 继承 第6章 接口与内部类 第7章 图形程序设计 第8章 事件处理 第9章 Swing用户界面组件 第10...

    JAVA基础课程讲义

    JAVA发展简史 12 JAVA为什么能够流行? 13 JAVA各版本的含义 13 JAVA技术体系架构 14 JAVA的特性和优势 14 JAVA应用程序的运行机制 15 JVM(JAVA VIRTUAL MACHINE) 16 Java运行时环境JRE(Java Runtime Environment) ...

    Java2核心技术.part5

    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目录 ...

    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 ...

    Java并发编程实战

    第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 活跃性与性能 第...

    Java2核心技术.part2

    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目录 ...

    疯狂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程序的...

    Java2核心技术.part3

    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目录 ...

    Java语言基础下载

    面向对象语言的发展简史 26 内容总结 29 独立实践 30 第三章:面向对象的程序设计 31 学习目标 31 类和对象的描述 32 声明类 32 声明属性 33 声明成员方法 34 源文件的布局 36 包的声明 36 包与目录的布局 38 内容...

    Java2核心技术.part1

    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选择...

    Java2核心技术.part6

    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目录 ...

    Java2核心技术.part4

    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目录 ...

Global site tag (gtag.js) - Google Analytics