Java多线程设计模式(一)
Java多线程基础
Thread类的run方法和start方法
- 启动新的线程
- 调用run方法
线程的启动
- public class PrintThread extends Thread {
- private String msg;
- public PrintThread(String msg) {
- this.msg = msg;
- }
- public void run() {
- for(int i = 0; i < 10000; i++) {
- System.out.print(msg);
- }
- }
- public static void main(String[] args {
- new PrintThread("Good!").start();
- new PrintThread("Nice!").start();
- }
- }
public interface Runnable {public abstract void run();}已实现Runnable接口的类必须实现run()方法。
- public class PrintThread implements Runnable {
- private String msg;
- public PrintThread(String msg) {
- this.msg = msg;
- }
- public void run() {
- for(int i = 0; i < 10000; i++) {
- System.out.print(msg);
- }
- }
- public static void main(String[] args {
- new Thread(new PrintThread("Good!")).start();
- new Thread(new PrintThread("Nice!")).start();
- }
- }
线程的暂时停在
线程的共享互斥
一个方法加上关键字synchronized声明之后,就可以让1个线程操作这个方法。这种线程称为synchronized方法,又称为同步方法。
synchronized实例方法就是使用this锁定去做线程的共享互斥。synchronized类方法是使用该类的类对象的锁定去做线程的共享互斥
线程的协调
有实例都有一个wait set,wait
set是一个在执行该实例的wait方法时、操作停止的线程的集合。一个执行wait()方法时,线程便会暂时停止操作,进入wait
set这个休息室。如欲执行wait()方法,线程需获取锁定。但是当线程进入wait
set时,已经释放了该实例的锁定。使用notify()方法时,可从wait
set里抓取一个线程。线程必须有调用实例的锁定,才能执行notify()方法,这跟调用wait()方法一样。使用notifyAll()方法时,会
将所有在wait
set里等待的线程全部拿出来。同样,线程必须获取调用实例的锁定,才能调用notifyAll()方法。注意,wait()、notify()、
notifyAll()方法都是Object类的方法。
Single Threaded Execution Pattern
使用该模式来限制同时只让一个线程运行。先看一个不是使用该模式的多线程的例子,并非线程安全(Thread-safe)的Gate类:
- public class Main {
- public static void main(String[] args) {
- System.out.println("Testing Gate, hit CTRC+C to exit.");
- Gate gate = new Gate();
- new UserThread(gate, "Alice", "Alaska").start();
- new UserThread(gate, "Bobby", "Brazil").start();
- new UserThread(gate, "Chris", "Canada").start();
- }
- }
- public class Gate {
- private int counter = 0;
- private String name = "Nobody";
- private String address = "Nowhere";
- public void pass(String name, String address) {
- this.counter++;
- this.name = name;
- this.address = address;
- check();
- }
- public String toString() {
- return "No. " + counter + " name: " + name + ", address: " + address;
- }
- private void check() {
- if (name.charAt(0) != address.charAt(0)) {
- System.out.println("******BROKEN*******" + toString());
- }
- }
- public class UserThread extends Thread {
- private final Gate gate;
- private final String myname;
- private final String myaddress;
- public UserThread (Gate gate, String myname, String myaddress) {
- this.gate = gate;
- this.myname = myname;
- this.myaddress =myaddress;
- }
- public void run() {
- System.out.println(this.myname + "Begin");
- while(true) {
- gate.pass(this.myname,myaddress);
- }
- }
- }
- }
执行看看。
由于Gate类不是线程安全的,当多个线程对其的状态进行更改时,会出现与期望不符的结果。可以通过将Gate类改造成线程安全的类来解决这个问题。线程安全最简单的方法即是使用本模式,使同一时间只让一个线程执行。线程安全版的Gate类如下:
- public class Gate {
- private int counter = 0;
- private String name = "Nobody";
- private String address = "Nowhere";
- public synchronized void pass(String name, String address) {
- this.counter++;
- this.name = name;
- this.address = address;
- check();
- }
- public synchronized String toString() {
- return "No. " + counter + " name: " + name + ", address: " + address;
- }
- private void check() {
- if (name.charAt(0) != address.charAt(0)) {
- System.out.println("******BROKEN*******" + toString());
- }
- }
- }
即在pass()方法和toString()方法前面加上synchronized关键字,这样Gate类就是线程安全的类了。synchronized锁扮演的角色就是对共享资源的保护。
Single Threaded Execution Pattern的参与者:
SharedResource(共享资源):在本例中Gate类(准确说是Gate类的实例)是这个SharedResource。
SharedResource是可由多个线程访问的类。在该模式下,我们对unsafeMethod加以防护,限制同时只能有一个线程进行访问,在
Java语言中,将unsafeMethod定义成synchronized方法,就可以实现这个目标。这个必须只让单线程执行的程序范围,我们称为临界
区(critical section)
何时该适用Single Threaded Execution Pattern,当SharedResouce实例可能同时被多个线程访问的时候,并且SharedResource的状态可能变化的时候。
另外注意,使用Single Threaded Execution Pattern 时可能会发生死锁(deadlock)的危险。
性能问题,临界区的大小与执行性能直接相关。首先,获取锁定需要花费时间,其次,线程冲突时必须等待。所以,尽可能缩小临界区的范围,以减少出现线程冲突的机会,可抑制性能的降低。
另外一个问题,synchronized是获取谁的锁定来保护呢?如果实例不同,那么锁定也不同。如果有多个不同的实例,那么多个线程仍然可以分别执行不同实例的synchronized方法。
synchronized方法同时只有一个线程可以执行,当有一个线程正在执行synchronized方法时,其他线程不能进入这个方法。从多线程的角
度看,synchronized方法是原子操作(atomic
operation)。在Java语言规格上,long和double的赋值操作并不是原子的。可以在类属性字段前面加上volatile关键字将所有对
该字段的操作变为原子的。
Immutable Pattern
不变模式,该模式的语义与GoF定义的设计模式的不变模式是一样的,即通过定义不变类,来实现线程的安全性。由于类的实例一旦生成,其状态将不会变化,顾其天生就是线程安全的。
使用Immutable Pattern 的Person类
- public final class Person {
- private final String name;
- private final String address;
- public Person(String name, String address) {
- this.name = name;
- this.address = address;
- }
- public String getName() {
- return this.name;
- }
- public String getAddress() {
- return this.address;
- }
- public String toString() {
- return "[ Person: name =" + name + ", address = " + address + " ]";
- }
- }
- public class Main() {
- public static void main(String[] args){
- Person alice = new Person("Alice", "Alaska");
- new PrintPersonThread(alice).start();
- new PrintPersonThread(alice).start();
- new PrintPersonThread(alice).start();
- }
- }
- public class PrintPersonThread extends Thread {
- private Person person;
- public PrintPersonThread(Person persion) {
- this.person = person;
- }
- public void run() {
- while(true) {
- System.out.println(Thread.currentThread().getName() + " prints " + person);
- }
- }
- }
Immutable Pattern的参与者为不变者。Immutable
Pattern何时适用,当实例产生后,状态不再变化;实例需要共享,而且访问频繁时。Java语言的标准类库中有许多使用Immutable的类,例
如:java.lang.String、java.lang.Integer\java.lang.Short这些基本类型的包装类。
Java多线程设计模式(一)的更多相关文章
- java多线程设计模式
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt220 java多线程设计模式 java语言已经内置了多线程支持,所有实现Ru ...
- [温故]图解java多线程设计模式(一)
去年看完的<图解java多线程设计模式>,可惜当时没做笔记,导致后来忘了许多东西,打算再温习下这本书,顺便在这里记录一下~ 1.顺序执行.并行.并发 顺序执行:多个操作按照顺序依次执行. ...
- Java多线程设计模式(4)线程池模式
前序: Thread-Per-Message Pattern,是一种对于每个命令或请求,都分配一个线程,由这个线程执行工作.它将“委托消息的一端”和“执行消息的一端”用两个不同的线程来实现.该线程模式 ...
- Java多线程设计模式(四)
目录(?)[-] Future Pattern Two-Phase Termination Pattern Thread-Specific Storage Pattern Active Object ...
- Java多线程设计模式(三)
目录(?)[-] Read-Wirte Lock Pattern Thread-Per-Message Pattern Worker Thread Pattern Read-Wirte Lock ...
- Java多线程设计模式(二)
目录(?)[-] Guarded Suspension Pattern Balking Pattern Producer-Consumer Pattern Guarded Suspensi ...
- Java多线程设计模式(1)
1 线程中的几个方法解释 Thread.sleep(long 毫秒) 在指定的时间内让当前线程休眠,将控制权交给其他线程,休眠的线程依旧拥有它所占用的锁, Thread.yield(); 暂停或者放弃 ...
- Java多线程设计模式系列
通过几天的认真阅读,发现这是一本难得一见的好书,为了加深巩固学习成功,我打算将书中的例子全部自己实现一遍,特此记录下来也方便其他朋友学习. 第一章,java语言的线程 单线程程序:打印10000次go ...
- java多线程设计模式(3)读写锁模式
1 Read-Write Lock Pattern Read-Write Lock Pattern是一种将对于共享资源的访问与修改操作分离,称为读写分离.即访问是reader,修改是write,用单独 ...
随机推荐
- mysql导出文本文件,加分隔符
从mysql导出,再导入到oracle #!/bin/sh cd /u03/tools/machine_info rm -f data/machine_info.txt mysql -u用户名 -p密 ...
- REST理解
内容摘自:<Spring REST> REST是什么:REST是一种软件架构风格,它由建立规模可扩展的web服务的最佳实践和指南构成. 资源: 一切可被访问和操作的东西.资源标识:URI( ...
- 回归问题中代价函数选择的概率解释(Probabilistic interpretation)
在我们遇到回归问题时,例如前面提到的线性回归,我们总是选择最小而成作为代价函数,形式如下: 这个时候,我们可能就会有疑问了,我们为什么要这样来选择代价函数呢?一种解释是使我们的预测值和我们训练样本的真 ...
- 关于Floyd-Warshall算法由前趋矩阵计算出的最短路径反映出了算法的执行过程特性的证明
引言:Floyd-Warshall算法作为经典的动态规划算法,能够在O(n3)复杂度之内计算出所有点对之间的最短路径,且由于其常数较小,对于中等规模数据运行效率依然可观.算法共使用n此迭代,n为顶点个 ...
- Spring源码研究--下载-编译-导入eclipse-验证
一,环境配置 操作系统:Unbutu14.04LTS JDK: 1.8.0_40 git: 1.9.1 gradle: 2.2.1 二,源码下载-编译-导入eclipse-验证 1,下载 使用git直 ...
- python:while 语句的使用方法
while语句: count = 0 while True: print(count) count += 1 if count == 10: break 实例: 计算n!,若:n = 5:则:n! = ...
- linux开机自检配置文件fstab变只读无法修改问题
控制linux开机自检的配置文件是/etc/fstab,在最近用的服务器中,发现fstab变成了只读权限,无法修改. 解决方法:RH5下,因磁盘改变,而导致系统停在Ctrl+d,此时需输入密码进入修改 ...
- 《Head First 设计模式》观后感——专业并不一定是深奥和枯燥
<Head First 设计模式>观后感——专业并不一定是深奥和枯燥 说起设计模式,我想做程序的朋友都不会感到陌生,这就像是软件里的缩写一样,可以快速的表达一系列的意思. 但是纵观市面上的 ...
- PHP获取当前文件路径
__FILE__ 是当前路径+文件名dirname(__FILE__)返回当前文件路径的路径部分 例如当前文件是 /home/data/demo/demo.php ,则 __FILE__ 得到的就是完 ...
- spring4-4-jdbc-02
1.简化 JDBC 模板查询 每次使用都创建一个 JdbcTemplate 的新实例, 这种做法效率很低下. JdbcTemplate 类被设计成为线程安全的, 所以可以再 IOC 容器中声明它的单个 ...