多线程

  • 一、线程和多线程
  • 1、线程的概念
  • 2、线程的结构
  • 3、线程的状态
  • 二、创建线程
  • 1、继承Thread类创建线程
  • 2、实现Runnable接口创建线程
  • 三、线程的基本控制
  • 1、线程的启动
  • 2、线程的调度
  • 3、结束线程
  • 4、挂起线程
  • 四、线程的互斥


一、线程和多线程

1、线程的概念
  • 进程:在程序要投入运行时,系统从程序入口开始按语句的顺序(包括顺序、分支和循环结构)完成相应指令直至结尾,再从出口退出,整个程序结束。
  • 线程是比进程更小的执行单位
  • 线程是进程的一部分
2、线程的结构
  • 线程的结构
    线程的结构
      在Java中,线程由以下3部分组成。
      ·虚拟CPU,封装在java.lang.Thread类中,它控制着整个线程的运行。
      ·执行的代码,传递给Thread类,由Thread类控制按序执行。
    ·处理的数据,传递给Thread类,是在代码执行过程中所要处理的数据。
3、线程的状态

多线程 架构 多线程结构_java

  • 线程是通过包java.lang中定义的类Thread来实现的
  • Thread类本身只是线程的虚拟CPU
  • 线程一共有4种状态,分别是新建(New)、可运行状态(Runnable)、死亡(Dead)及阻塞(Blocked)。
  • 可运行状态
    线程已经启动,处于线程的run()方法之中。
    可以运行但没在运行的线程都排在一个队列中,这个队列称为就绪队列。
    调用线程的start()方法可使线程处于可运行状态。
  • 死亡
    线程死亡的原因有两个:一是run()方法中最后一个语句执行完毕,二是当线程遇到异常退出时便进入了死亡状态。
  • 阻塞
    一个正在执行的线程因特殊原因,被暂停执行,就进入阻塞状态。阻塞时线程不能进入就绪队列排队,必须等到引起阻塞的原因消除,才可重新进入队列排队。引起阻塞的原因很多,不同原因要用不同的方法解除。sleep()和wait()是两个常用的引起阻塞的方法。

二、创建线程

1、继承Thread类创建线程
  • 创建线程有两种方法,一种是定义一个继承Thread类的子类,另一种是实现Runnable接口。
  • 用Thread类的子类创建线程的过程包括以下3步。
      1)从Thread类派生出一个子类,在类中一定要实现run()。
      class Lefthand extends Thread {
         public void run(){…} //线程体
      }
      2)然后用该类创建一个对象。如
      Lefthand left=new Lefthand( );。
      3)用start()方法启动线程。如left.start( );。
  • 用Thread类的子类创建线程

多线程 架构 多线程结构_java_02


多线程 架构 多线程结构_java_03

2、实现Runnable接口创建线程
  • Runnable是Java中用以实现线程的接口
  • Runnable接口中只定义了一个方法就是run()方法,也就是线程体。
  • 用Runnable接口实现多线程时,也必须实现run()方法,也需要使用start()启动线程
  • 编写线程体
public class xyz implements Runnable {
      int i;
      public void run( ) {
         while (true) {
             System.out. println (" Hello " + i++);
                 }
           }
  }
  • Runnable接口创建线程

三、线程的基本控制

1、线程的启动
  • API中提供了以下有关线程的操作方法。
      ·start():启动线程对象,让线程从新建状态转为就绪状态。
      ·run():用来定义线程对象被调度之后所执行的操作,用户必须重写run( )方法。
      ·yield():强制终止线程的执行。
      ·isAlive():测试当前线程是否在活动。
      ·sleep(int millsecond):使线程休眠一段时间,时间长短由millsecond决定,单位为ms。
      ·void wait():使线程处于等待状态。
2、线程的调度
  • 线程调度通常是抢占式
  • 每个线程都有一个优先级,Java的线程调度采用如下的优先级策略。
      ·优先级高的先执行,优先级低的后执行。
      ·每个线程创建时都会被自动分配一个优先级,默认时,继承其父类的优先级。
      ·任务紧急的线程,其优先级较高。
      ·同优先级的线程按“先进先出”的调度原则。
  • Thread类有3个与线程优先级有关的静态量,分别如下。
      ·MAX_PRIORITY:最高优先级,值为10。
      ·MIN_PRIORITY:最低优先级,值为1。
      ·NORM_PRIORITY:默认优先级,值为5。
  • java.lang.Thread类中有关优先级的几个常用方法如下。
      ·void setPriority(int newPriority):重置线程优先级。
      ·int getPriority():获得当前线程的优先级。
      ·static void yield( ):暂停当前正在执行的线程,即让当前线程放弃执行权。
  • 调度
public class Xyz implements Runnable {
      public void run( ) {
          while(true) {
              …… //执行若干操作
             //给其他线程运行的机会
             try{
             Thread.sleep(10) ;
             }catch(InterruptedException e) { }
            }
        }
  }
3、结束线程

线程运行完

  • interrupt( )方法中断线程的执行。
  • Thread类中的静态方法currentThread( )来引用正在运行的线程。
  • isAlive()来获取一个线程是否还在活动状态的信息。
4、挂起线程
  • sleep()方法用于暂时停止一个线程的执行。
  • wait()方法导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,才能唤醒线程。
  • join()方法将引起现行线程等待,直至join()方法所调用的线程结束。

四、线程的互斥

  • 栈具有“后进先出”模式
  • 栈示例
class Stack{
     int idx = 0 ;
     char data[ ] = new char[6];
     public void push (char c){
         data[idx] = c ;
         idx ++ ;
     }
     public char pop(){
         idx --;
         return data[idx] ;
     }
  }
  • 在Java语言中,有两种方法可以实现“对象互斥锁”。
      ·用关键字volatile来声明一个共享数据(变量)。
      ·用关键字synchronized来声明操作共享数据的一个方法或一段代码。
  • 锁定标志
class stack {
     int idx = 0 ;
     char data[ ] = new char[6] ;
     public void push (char c ) {
       synchronized (this) { // 增加同步标志
       data[idx] = c ;
       idx ++ ;
      }
    }
  }

synchronized( )语句的标准写法为:
  public void push (char c) {
     synchronized ( this ) {
     …
     }
  }