`

Java多线程基础

    博客分类:
  • 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.   
  12. public static void main(String[] args {  
  13. new PrintThread("Good!").start();  
  14. new PrintThread("Nice!").start();  
  15. }  
  16. }  

 

在main()方法里,先建立PrintThread类的实例后,调用该实例的 start()方法启动线程。建立“PrintThread类的实例”和“启动该实例所对应的线程”是两个完全不同的处理。即使已经建立了实例,仍然必须 等到调用start()方法才会启动线程。主线程在main()方法里启动两个线程,因为main()方法会立即结束,所以主线程也会立即结束,不过整个 程序还没有结束,一直要等到所有线程都已经结束,程序才会结束。不过这里不包括daemon thread。利用Runnable接口

 

Runnable接口是java.lang Package里的接口,声明方法如下:

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

  1.    
  2. public class PrintThread implements Runnable {  
  3. private String msg;  
  4. public PrintThread(String msg) {  
  5. this.msg = msg;  
  6. }  
  7. public void run() {  
  8. for(int i = 0; i < 10000; i++) {  
  9. System.out.print(msg);  
  10. }  
  11. }  
  12.   
  13. public static void main(String[] args {  
  14. new Thread(new PrintThread("Good!")).start();  
  15. new Thread(new PrintThread("Nice!")).start();  
  16. }  
  17. }  

 

不管是利用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.   
  11. public class Gate {  
  12. private int counter = 0;  
  13. private String name = "Nobody";  
  14. private String address = "Nowhere";  
  15. public void pass(String name, String address) {  
  16. this.counter++;  
  17. this.name = name;  
  18. this.address = address;  
  19. check();  
  20. }  
  21. public String toString() {  
  22. return "No. " + counter + " name: " + name + ", address: " + address;  
  23. }  
  24. private void check() {  
  25. if (name.charAt(0) != address.charAt(0)) {  
  26. System.out.println("******BROKEN*******" + toString());  
  27. }  
  28. }  
  29.   
  30. public class UserThread extends Thread {  
  31. private final Gate gate;  
  32. private final String myname;  
  33. private final String myaddress;  
  34. public UserThread (Gate gate, String myname, String myaddress) {  
  35. this.gate = gate;  
  36. this.myname = myname;  
  37. this.myaddress =myaddress;  
  38. }  
  39. public void run() {  
  40. System.out.println(this.myname + "Begin");  
  41. while(true) {  
  42. gate.pass(this.myname,myaddress);  
  43. }  
  44. }  
  45. }  
  46. }  

执行看看。
由于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.   
  19. public class Main() {  
  20. public static void main(String[] args){  
  21. Person alice = new Person("Alice""Alaska");  
  22. new PrintPersonThread(alice).start();  
  23. new PrintPersonThread(alice).start();  
  24. new PrintPersonThread(alice).start();  
  25. }  
  26. }  
  27.   
  28. public class PrintPersonThread extends Thread {  
  29. private Person person;  
  30. public PrintPersonThread(Person persion) {  
  31. this.person = person;  
  32. }  
  33. public void run() {  
  34. while(true) {  
  35. System.out.println(Thread.currentThread().getName() + " prints " + person);  
  36. }  
  37. }   
  38. }  

 

 
 
分享到:
评论

相关推荐

    JAVA多线程基础演练DEMO

    这个"JAVA多线程基础演练DEMO"提供了一些基础示例,帮助开发者更好地理解和掌握多线程的基本概念和用法。以下将详细讲解Java多线程的相关知识点: 1. **线程的创建** - **继承Thread类**:创建一个新类,继承自`...

    Java多线程干货系列(1)Java多线程基础编程开发技术

    Java多线程是Java编程中的重要...以上内容仅涵盖了Java多线程基础编程的一部分知识点,实际开发中还需要关注更多的并发控制策略、性能优化和调试技巧。对于深入理解Java多线程,还需要学习和实践更多相关的高级特性。

    java多线程基础资料

    Java多线程是Java编程中的一个...以上只是Java多线程基础知识的一部分,深入学习还包括线程池的配置与优化、线程安全的设计模式、并发工具类的使用等。理解和掌握这些知识点对于编写高效、稳定的多线程程序至关重要。

    java多线程基础说课PPT教案.pptx

    java多线程基础说课PPT教案.pptx

    java多线程基础篇讲解

    Java多线程基础篇讲解是针对初学者设计的教程,旨在用简洁明了的语言帮助学习者更容易理解多线程的概念和应用。多线程编程在现代计算机系统中扮演着重要角色,尤其在CPU主频发展遇到瓶颈的情况下,通过超线程技术和...

    java多线程基础知识

    Java多线程基础知识 Java多线程基础知识是Java编程语言中的一项重要技术,用于提高程序的执行效率和响应速度。在这里,我们将详细介绍Java多线程基础知识的相关概念和技术。 一、程序、进程和线程 程序(Program...

    Java多线程基础-01、数组概述.rar

    本资料“Java多线程基础-01、数组概述”将带你入门Java的多线程世界,并结合数组这一基本数据结构进行讲解。 首先,我们需要理解什么是线程。线程是操作系统分配CPU时间的基本单位,一个进程可以有多个线程,它们...

    java多线程基础学习文档

    以上就是Java多线程基础学习的一些关键知识点,理解并掌握这些内容对于进行高效的多线程编程至关重要。在实际开发中,还需要根据具体需求选择合适的线程模型和同步机制,以实现高效、安全的并发程序。

    Java 多线程基础笔记

    Java 多线程基础笔记

    Java多线程基础-03、数组定义方式二、元素默认值规则.rar

    总之,Java多线程基础是高效编程的关键,而理解数组定义和元素默认值规则则是构建安全、健壮的多线程程序的基础。通过合理运用多线程技术和掌握数组的内在特性,你可以编写出更加高性能、可扩展的Java应用程序。

    Java多线程基础-02、数组定义方式一、访问、注意事项.rar

    在Java编程语言中,多线程是程序设计中的一个重要概念,尤其在处理高并发和资源优化的场景下...通过观看"Java多线程基础-02、数组定义方式一、访问、注意事项.mp4"这个视频教程,你将能更深入地学习这些重要的知识点。

    java多线程基础说课学习课程.pptx

    java多线程基础说课学习课程.pptx

    java多线程基础说课学习教案.pptx

    java多线程基础说课学习教案.pptx

    java多线程基础说课PPT学习教案.pptx

    java多线程基础说课PPT学习教案.pptx

    java多线程设计

    一、Java多线程基础 1. 线程的创建:Java提供了两种创建线程的方式——继承Thread类和实现Runnable接口。继承Thread类可以直接创建一个新的线程类,而实现Runnable接口则可以将线程逻辑封装在任何类中,更利于代码...

    java多线程示例

    一、Java多线程基础 1. 创建线程: - 继承Thread类:创建一个新的类,继承自Thread类,重写其run()方法,然后创建该类的实例并调用start()方法。 - 实现Runnable接口:创建一个实现了Runnable接口的类,实现run()...

    详细剖析JAVA多线程案例教学

    #### 二、Java多线程基础 ##### 1. 线程的概念 线程是程序执行流的最小单元,是操作系统能够进行运算调度的最小单位。一个标准的解释是:“线程是一种轻量级进程,它是进程内的一个执行实体。”Java中的每个程序至少...

    Java 多线程介绍

    ### Java多线程基础 #### 线程的生命周期 Java线程有多种状态,主要包括: 1. **New(新建)**:当使用`new`关键字创建一个新的线程对象但尚未调用`start()`方法时,线程处于New状态。 2. **Runnable(可运行)**...

    JAVA多线程教材

    1. **Java多线程基础知识**:Java多线程允许程序同时执行多个任务,这是通过创建和管理线程实现的。Java提供了两种创建线程的方式:继承Thread类和实现Runnable接口。线程的状态包括新建、就绪、运行、阻塞和终止,...

    java多线程作业.docx

    #### 二、Java多线程基础 1. **线程创建**: - 继承`Thread`类。 - 实现`Runnable`接口。 2. **线程调度**: - 线程调度是由操作系统完成的,Java虚拟机通过与操作系统交互来管理线程的执行。 - Java中线程...

Global site tag (gtag.js) - Google Analytics