- 浏览: 327537 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (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)
引言
首先问这样一个问题,如果提到Java多线程编程,你会想到什么?
volatile、synchronized关键字?
竞争和同步?
锁机制?
线程安全问题?
线程池和队列?
好吧,请原谅我在这里卖的关子,其实这些都对,但是又不足够全面,如果我们这样来谈论Java多线程会不会全面一些:
模型:JMM(Java内存模型)和JCM(Java并发模型)
使用:JDK中的并发包
实践:怎样写线程安全的代码
除错:使用工具来分析并发问题
……
可是,这未免太死板了,不是么?
不如换一个思路,我们少谈一些很容易查到的语法,不妨从历史的角度看看Java在多线程编程方面是怎样进化的,这个过程中,它做了哪些正确的决定,犯了哪些错误,未来又会有怎样的发展趋势?
另外,还有一点要说是,我希望通过大量的实例代码来说明这些事情。Linus说:“Talk is cheap, show me the code.”。下文涉及到的代码我已经上传,可以在此打包下载。
诞生
Java的基因来自于1990年12月Sun公司的一个内部项目,目标设备正是家用电器,但是C++的可移植性和API的易用性都让程序员反感。旨在解决这样的问题,于是又了Java的前身Oak语言,但是知道1995年3月,它正式更名为Java,才算Java语言真正的诞生。
JDK 1.0
1996年1月的JDK1.0版本,从一开始就确立了Java最基础的线程模型,并且,这样的线程模型再后续的修修补补中,并未发生实质性的变更,可以说是一个具有传承性的良好设计。
抢占式和协作式是两种常见的进程/线程调度方式,操作系统非常适合使用抢占式方式来调度它的进程,它给不同的进程分配时间片,对于长期无响应的进程,它有能力剥夺它的资源,甚至将其强行停止(如果采用协作式的方式,需要进程自觉、主动地释放资源,也许就不知道需要等到什么时候了)。Java语言一开始就采用协作式的方式,并且在后面发展的过程中,逐步废弃掉了粗暴的stop/resume/suspend这样的方法,它们是违背协作式的不良设计,转而采用wait/notify/sleep这样的两边线程配合行动的方式。
一种线程间的通信方式是使用中断:
package com.jiaozg.thread; public class InterruptCheck extends Thread { @Override public void run() { System.out.println("start"); while(true) { if(Thread.currentThread().isInterrupted()) { break; } } System.out.println("while exit"); } public static void main(String[] args) { Thread thread = new InterruptCheck(); thread.start(); try { sleep(2000); } catch (InterruptedException e) { } thread.interrupt(); } }
这是中断的一种使用方式,看起来就像是一个标志位,线程A设置这个标志位,线程B时不时地检查这个标志位。另外还有一种使用中断通信的方式,如下:
package com.jiaozg.thread; public class InterruptWait extends Thread { public static Object lock = new Object(); @Override public void run() { System.out.println("start"); synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().isInterrupted()); Thread.currentThread().interrupt(); // set interrupt flag again System.out.println(Thread.currentThread().isInterrupted()); e.printStackTrace(); } } } public static void main(String[] args) { Thread thread = new InterruptWait(); thread.start(); try { sleep(2000); } catch (InterruptedException e) { } thread.interrupt(); } }
在这种方式下,如果使用wait方法处于等待中的线程,被另一个线程使用中断唤醒,于是抛出InterruptedException,同时,中断标志清除,这时候我们通常会在捕获该异常的地方重新设置中断,以便后续的逻辑通过检查中断状态来了解该线程是如何结束的。
在比较稳定的JDK 1.0.2版本中,已经可以找到Thread和ThreadUsage这样的类,这也是线程模型中最核心的两个类。整个版本只包含了这样几个包:java.io、 java.util、java.net、java.awt和java.applet,所以说Java从一开始这个非常原始的版本就确立了一个持久的线程模型。
值得一提的是,在这个版本中,原子对象AtomicityXXX已经设计好了,这里给出一个例子,说明i++这种操作时非原子的,而使用原子对象可以保证++操作的原子性:
package com.jiaozg.thread; import java.util.concurrent.atomic.AtomicInteger; public class Atomicity { private static volatile int nonAtomicCounter = 0; private static volatile AtomicInteger atomicCounter = new AtomicInteger(0); private static int times = 0; public static void caculate() { times++; for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { public void run() { nonAtomicCounter++; atomicCounter.incrementAndGet(); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { } } public static void main(String[] args) { caculate(); while (nonAtomicCounter == 1000) { nonAtomicCounter = 0; atomicCounter.set(0); caculate(); } System.out.println("Non-atomic counter: " + times + ":" + nonAtomicCounter); System.out.println("Atomic counter: " + times + ":" + atomicCounter); } }
上面这个例子你也许需要跑几次才能看到效果,使用非原子性的++操作,结果经常小于1000。
对于锁的使用,网上可以找到各种说明,但表述都不够清晰。请看下面的代码:
package com.jiaozg.thread; public class Lock { private static Object o = new Object(); static Lock lock = new Lock(); // lock on dynamic method public synchronized void dynamicMethod() { System.out.println("dynamic method"); sleepSilently(2000); } // lock on static method public static synchronized void staticMethod() { System.out.println("static method"); sleepSilently(2000); } // lock on this public void thisBlock() { synchronized (this) { System.out.println("this block"); sleepSilently(2000); } } // lock on an object public void objectBlock() { synchronized (o) { System.out.println("dynamic block"); sleepSilently(2000); } } // lock on the class public static void classBlock() { synchronized (Lock.class) { System.out.println("static block"); sleepSilently(2000); } } private static void sleepSilently(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { // object lock test new Thread() { @Override public void run() { lock.dynamicMethod(); } }.start(); new Thread() { @Override public void run() { lock.thisBlock(); } }.start(); new Thread() { @Override public void run() { lock.objectBlock(); } }.start(); sleepSilently(3000); System.out.println(); // class lock test new Thread() { @Override public void run() { lock.staticMethod(); } }.start(); new Thread() { @Override public void run() { lock.classBlock(); } }.start(); } }
上面的例子可以反映对一个锁竞争的现象,结合上面的例子,理解下面这两条,就可以很容易理解synchronized关键字的使用:
非静态方法使用synchronized修饰,相当于synchronized(this)。
静态方法使用synchronized修饰,相当于synchronized(Lock.class)。
ref:http://developer.51cto.com/art/201209/357617.htm
发表评论
-
Java多线程基础总结九:Mina窥探
2012-10-29 14:54 1016一直以来的多线程 ... -
Java多线程基础总结八:ReentrantReadWriteLock
2012-10-29 14:23 898说到ReentrantReadWriteLock,首先 ... -
Java多线程基础总结七:ReentrantLock
2012-10-29 13:56 907之前总结了部分无锁机制的多线程基础,理想的状态当然是利用 ... -
Java多线程基础总结六:synchronized(2)
2012-10-27 22:36 838早在总结一时,我就尽量的把synchronized的重 ... -
Java多线程基础总结五:atomic
2012-10-26 17:41 904在简单介绍java.util.concurrent.a ... -
Java多线程基础总结四:ThreadLocal
2012-10-22 11:34 816说到ThreadLocal,首先说说这个类的命名。直观上 ... -
Java多线程基础总结三: volatile
2012-10-22 11:34 843前面的两篇总结简单 ... -
Java多线程基础总结二: Thread
2012-10-22 11:34 940对于Thread来说只想说两 ... -
Java多线程基础总结一: synchronized
2012-10-21 14:21 810最近写关于并发的小应用,才发现真的该好好的正视jav ... -
Java多线程发展简史(4)
2012-09-25 14:00 951JDK 6.0 JDK 6.0对锁做了一些优化,比如锁自旋、 ... -
Java多线程发展简史(3)
2012-09-25 11:47 935JDK 1.4 在2002年4月发布 ... -
Java多线程发展简史(2)
2012-09-24 17:29 815JDK 1.2 1998年年底的JDK1.2 ... -
Java 多线程的同步示例及对象锁机制
2012-09-22 16:49 1346java多线程的同步依靠的是对象锁机制,synchronize ... -
Java ThreadLocal解决线程安全问题
2012-08-29 18:37 4290ThreadLocal是什么 早在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在各种应用场景中表现出色。 了解Java应用程序的运行机制至关重要。Java程序在运行时需要JRE...
Java的发展简史表明,其名称来源于印度尼西亚的一个岛屿,同时又与程序员喜爱的咖啡相关。Java在互联网时代的成功主要归功于其跨平台特性,允许程序在不同操作系统上运行而无需重新编译。自1995年发布以来,Java已经...
1. **JAVA语言发展简史** - JAVA起初名为Oak,由Sun公司的Green Team小组创建,最初设计用于嵌入式系统。 - 1994年,随着互联网的兴起,Oak被重新定位并更名为JAVA,适应网络环境,因其在网络上的优势迅速获得广泛...
1. Java语言发展简史:Java语言由Sun Microsystems公司于1995年推出,它的设计目的是能够在任何设备上运行,保证了“一次编写,到处运行”的特性。Java经历了多个版本的迭代,目前广泛使用的版本为Java SE 8和Java ...
JAVA的发展简史可追溯到1995年,由Sun Microsystems推出,其设计理念是“一次编写,到处运行”。JAVA之所以流行,是因为它具有跨平台性、安全性和高性能,同时提供了丰富的类库。JAVA分为多个版本,如JDK(Java ...
Java 有着强大的多线程处理能力,多线程可以使程序有更好的交互性和实时性,并可以最大限度地利用多处理器系统。Java 为不同的操作系统实现了专门的多线程机制。 Java 简史: Java 技术起先是作为小型的电脑语言,...
- **多线程**:Java内置了对多线程的支持,可以轻松地开发出高性能的应用程序。 - **动态性**:Java具有高度动态性,可以通过反射机制在运行时获取类的信息,并通过动态代理等方式实现动态绑定。 - **体系结构中立...