Java多线程基础

Thread类的run方法和start方法

       Java语言写成的程序一定是先从主线程开始操作,所以必须在程序的某个位置启动新的线程,才能算是真正的多线程程序。start()方法是 Thread类的方法,调用start()方法,就会启动新的线程。请注意,被调用来启动线程的是start()方法,而非run()方法。调用 start()方法之后,Java执行处理系统会在背后启动新的线程。再由这个新的线程调用run()方法。调用start()方法,会有两个操作:
  • 启动新的线程
  • 调用run方法

线程的启动

利用Thread类的子类
  1. public class PrintThread extends Thread {
  2. private String msg;
  3. public PrintThread(String msg) {
  4. this.msg = msg;
  5. }
  6. public void run() {
  7. for(int i = 0; i < 10000; i++) {
  8. System.out.print(msg);
  9. }
  10. }
  11. public static void main(String[] args {
  12. new PrintThread("Good!").start();
  13. new PrintThread("Nice!").start();
  14. }
  15. }
在main()方法里,先建立PrintThread类的实例后,调用该实例的 start()方法启动线程。建立“PrintThread类的实例”和“启动该实例所对应的线程”是两个完全不同的处理。即使已经建立了实例,仍然必须 等到调用start()方法才会启动线程。主线程在main()方法里启动两个线程,因为main()方法会立即结束,所以主线程也会立即结束,不过整个 程序还没有结束,一直要等到所有线程都已经结束,程序才会结束。不过这里不包括daemon thread。利用Runnable接口
Runnable接口是java.lang Package里的接口,声明方法如下:

public interface Runnable {public abstract void run();}已实现Runnable接口的类必须实现run()方法。

  1. public class PrintThread implements Runnable {
  2. private String msg;
  3. public PrintThread(String msg) {
  4. this.msg = msg;
  5. }
  6. public void run() {
  7. for(int i = 0; i < 10000; i++) {
  8. System.out.print(msg);
  9. }
  10. }
  11. public static void main(String[] args {
  12. new Thread(new PrintThread("Good!")).start();
  13. new Thread(new PrintThread("Nice!")).start();
  14. }
  15. }
不管是利用Thread类的子类还是利用Runnable接口的实现类来启动线程,都是通过Thread类的start()方法。

线程的暂时停在

利用Thread类的sleep()方法即可暂时停在线程的执行操作。注意,sleep()方法是Thread类的静态方法。

线程的共享互斥

synchronized方法

一个方法加上关键字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类:

  1. public class Main {
  2. public static void main(String[] args) {
  3. System.out.println("Testing Gate, hit CTRC+C to exit.");
  4. Gate gate = new Gate();
  5. new UserThread(gate, "Alice", "Alaska").start();
  6. new UserThread(gate, "Bobby", "Brazil").start();
  7. new UserThread(gate, "Chris", "Canada").start();
  8. }
  9. }
  10. public class Gate {
  11. private int counter = 0;
  12. private String name = "Nobody";
  13. private String address = "Nowhere";
  14. public void pass(String name, String address) {
  15. this.counter++;
  16. this.name = name;
  17. this.address = address;
  18. check();
  19. }
  20. public String toString() {
  21. return "No. " + counter + " name: " + name + ", address: " + address;
  22. }
  23. private void check() {
  24. if (name.charAt(0) != address.charAt(0)) {
  25. System.out.println("******BROKEN*******" + toString());
  26. }
  27. }
  28. public class UserThread extends Thread {
  29. private final Gate gate;
  30. private final String myname;
  31. private final String myaddress;
  32. public UserThread (Gate gate, String myname, String myaddress) {
  33. this.gate = gate;
  34. this.myname = myname;
  35. this.myaddress =myaddress;
  36. }
  37. public void run() {
  38. System.out.println(this.myname + "Begin");
  39. while(true) {
  40. gate.pass(this.myname,myaddress);
  41. }
  42. }
  43. }
  44. }

执行看看。
由于Gate类不是线程安全的,当多个线程对其的状态进行更改时,会出现与期望不符的结果。可以通过将Gate类改造成线程安全的类来解决这个问题。线程安全最简单的方法即是使用本模式,使同一时间只让一个线程执行。线程安全版的Gate类如下:

  1. public class Gate {
  2. private int counter = 0;
  3. private String name = "Nobody";
  4. private String address = "Nowhere";
  5. public synchronized void pass(String name, String address) {
  6. this.counter++;
  7. this.name = name;
  8. this.address = address;
  9. check();
  10. }
  11. public synchronized String toString() {
  12. return "No. " + counter + " name: " + name + ", address: " + address;
  13. }
  14. private void check() {
  15. if (name.charAt(0) != address.charAt(0)) {
  16. System.out.println("******BROKEN*******" + toString());
  17. }
  18. }
  19. }

即在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类

  1. public final class Person {
  2. private final String name;
  3. private final String address;
  4. public Person(String name, String address) {
  5. this.name = name;
  6. this.address = address;
  7. }
  8. public String getName() {
  9. return this.name;
  10. }
  11. public String getAddress() {
  12. return this.address;
  13. }
  14. public String toString() {
  15. return "[ Person: name =" + name + ", address = " + address + " ]";
  16. }
  17. }
  18. public class Main() {
  19. public static void main(String[] args){
  20. Person alice = new Person("Alice", "Alaska");
  21. new PrintPersonThread(alice).start();
  22. new PrintPersonThread(alice).start();
  23. new PrintPersonThread(alice).start();
  24. }
  25. }
  26. public class PrintPersonThread extends Thread {
  27. private Person person;
  28. public PrintPersonThread(Person persion) {
  29. this.person = person;
  30. }
  31. public void run() {
  32. while(true) {
  33. System.out.println(Thread.currentThread().getName() + " prints " + person);
  34. }
  35. }
  36. }

Immutable Pattern的参与者为不变者。Immutable
Pattern何时适用,当实例产生后,状态不再变化;实例需要共享,而且访问频繁时。Java语言的标准类库中有许多使用Immutable的类,例
如:java.lang.String、java.lang.Integer\java.lang.Short这些基本类型的包装类。

转载自:http://blog.csdn.net/shenzhen_liubin/article/details/9736485

Java多线程设计模式(一)的更多相关文章

  1. java多线程设计模式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt220 java多线程设计模式 java语言已经内置了多线程支持,所有实现Ru ...

  2. [温故]图解java多线程设计模式(一)

    去年看完的<图解java多线程设计模式>,可惜当时没做笔记,导致后来忘了许多东西,打算再温习下这本书,顺便在这里记录一下~  1.顺序执行.并行.并发 顺序执行:多个操作按照顺序依次执行. ...

  3. Java多线程设计模式(4)线程池模式

    前序: Thread-Per-Message Pattern,是一种对于每个命令或请求,都分配一个线程,由这个线程执行工作.它将“委托消息的一端”和“执行消息的一端”用两个不同的线程来实现.该线程模式 ...

  4. Java多线程设计模式(四)

    目录(?)[-] Future Pattern Two-Phase Termination Pattern Thread-Specific Storage Pattern Active Object ...

  5. Java多线程设计模式(三)

    目录(?)[-] Read-Wirte Lock Pattern Thread-Per-Message Pattern Worker Thread Pattern   Read-Wirte Lock ...

  6. Java多线程设计模式(二)

        目录(?)[-] Guarded Suspension Pattern Balking Pattern Producer-Consumer Pattern   Guarded Suspensi ...

  7. Java多线程设计模式(1)

    1 线程中的几个方法解释 Thread.sleep(long 毫秒) 在指定的时间内让当前线程休眠,将控制权交给其他线程,休眠的线程依旧拥有它所占用的锁, Thread.yield(); 暂停或者放弃 ...

  8. Java多线程设计模式系列

    通过几天的认真阅读,发现这是一本难得一见的好书,为了加深巩固学习成功,我打算将书中的例子全部自己实现一遍,特此记录下来也方便其他朋友学习. 第一章,java语言的线程 单线程程序:打印10000次go ...

  9. java多线程设计模式(3)读写锁模式

    1 Read-Write Lock Pattern Read-Write Lock Pattern是一种将对于共享资源的访问与修改操作分离,称为读写分离.即访问是reader,修改是write,用单独 ...

随机推荐

  1. Varnish,Nginx搭建缓存服务器

    Varnish,Nginx搭建缓存服务器 一. varnish 1.安装pcre库,兼容正则表达式 # tar -zxvf pcre-8.10.tar.gz # cd pcre-8.10 # ./co ...

  2. 第二章:Android Studio概述(二)[学习Android Studio汉化教程]

    The Main Menu Bar 主菜单栏  主菜单栏位于Android Studio的最上面,你几乎可以利用主菜单和其子菜单来执行任何操作.不像Android Studio中其他的一些菜单,主菜单 ...

  3. [OpenCV Qt教程] 在Qt图形界面中显示OpenCV图像的OpenGL Widget(第二部分)

    本文译自:http://www.robot-home.it/blog/en/software/tutorial-opencv-qt-opengl-widget-per-visualizzare-imm ...

  4. Rhythmk 一步一步学 JAVA(7): jsp 自定义标签

    1.实现Tag接口: TagSupport类实现了Tag接口,为我们提供了4个重要的方法(见表6-5). 1.1. TagSupport类中的常用方法           int doStartTag ...

  5. IP流量重放与pcap文件格式解析

    (作者:燕云   出处:http://www.cnblogs.com/SwordTao/ 欢迎转载,但也请保留这段声明,谢谢!)   君不见 黄河之水 天上来 奔流到海不复回   君不见 高堂明镜 悲 ...

  6. python十个博客

    1.首先第一个肯定是毋庸置疑的Planet Python这是最出名的python博客其中之一,快去看看,我希望你能找到对你有用的东西,昨天它还更新了呢! 2.第二个博客是lucumr,博主是flask ...

  7. 【MongoDB】MongoDB 性能优化 - BI查询聚合

    在BI服务中通过查询聚合语句分析定位慢查询/聚合分析,小结如下: 慢查询定位: 通过Profile分析慢查询 对于查询优化: 通过添加相应索引提升查询速度: 对于聚合大数据方案: 首先要说明的一个问题 ...

  8. [ 原创 ] Linux下查找指定类型文件以及删除

    find ./ -name "*.lok"   // 查找文件find ./ -name "*.lok" |xargs rm -fr  // 查找文件并删除

  9. Linux运维跳槽必备的40道面试精华题

    过一次年,结婚.存款.父母养老,一系列向钱看的事都在碾压我们本来还挺简单的神经,但难过没有出路,唯有找到好的方法和事业方向,才能实现一步一个脚印的逆袭. 下面是一名资深Linux运维求职数十家公司总结 ...

  10. python 常用模块 time random os模块 sys模块 json & pickle shelve模块 xml模块 configparser hashlib subprocess logging re正则

    python 常用模块 time random os模块 sys模块 json & pickle shelve模块 xml模块 configparser hashlib  subprocess ...