自学软件开发(PPT版)本章主要讲述如下内容:多线程的概念;线程的生命周期;多线程编程中的常量和方法;线程调度方法;资源冲突与协调;线程之间的通信。19.1简介9.1.1什么是线程•一般来说,我们把正在计算机中执行的程序叫做“进程”(Process),而不将其称为程序(Program)。所谓“线程”(Thread),是“进程”中某个单一顺序的控制流。•线程在程序中是独立的、并发的执行路径•线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。江西新华电脑学院•进程就是在某种程度上相互隔离的、独立运行的程序。•线程是进程内部的单一控制序列流。一个进程可以具有多个并发的线程。•进程可以支持多个线程,它们看似同时执行,但互相之间并不同步。(CPU只是将时间切割为时间片,然后将时间片分配给这些线程,CPU的高速计算能力,给人的感觉就像是多个线程在同时执行一样。)•进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程的全局变量和资源。这一方面为编程带来了方便,但另一方面也容易造成冲突。线程和进程39.3JAVA线程9.3.1实现方式•Java程序通过流控制来执行程序流,程序中单个顺序的流控制称为线程,多线程则指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务•Java里面实现多线程,有2个方法–继承Thread类(位于java.lang包内)–实现Runnable接口•一般鼓励使用第二种方法,因为Java里面只允许单一继承,但允许实现多个接口。第二个方法更加灵活4•每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的–方法run()称为线程体–使用start()方法启动线程•启动线程是使线程进入到可运行(runnable)状态,并不一定立即开始执行该线程9.3JAVA线程5publicclassHelloThreadextendsThread{publicvoidrun(){System.out.println(Iextend\Thread\.);}}Java实现线程,方法一:继承Thread继承Thread线程体,所有的操作都发生在线程体中publicclassTestHello{publicstaticvoidmain(String[]args){HelloThreadhelloThread=newHelloThread();helloThread.start();}}start()方法启动线程运行结果:IextendThread.Java实现线程,方法二:实现Runnable接口publicclassHelloRunnerimplementsRunnable{publicvoidrun(){System.out.println(Iimplements\“Runable\.);}}实现Runnable线程体,所有的操作都发生在线程体中publicclassTestHello{publicstaticvoidmain(String[]args){HelloRunnerrunner=newHelloRunner();Threadthread=newThread(runner);thread.start();}}start()方法启动线程运行结果:IimplementRunnable.启动线程是使线程进入到可运行(runnable)状态,并不一定立即开始执行该线程实例化线程实例化线程6两种创建线程方法的比较•使用Runnable接口–形成清晰的模型;–还可以从其他类继承;–保持程序风格的一致性。•直接继承Thread类–不能再从其他类继承;–编写简单,可以直接操纵线程7线程属性•线程体–所有的操作都发生在线程体中,在Java中线程体是从Thread类继承的run()方法,或实现Runnable接口的类中的run()方法。当线程产生并初始化后,实时系统调用它的run()方法。run()方法内的代码实现所产生线程的行为,它是线程的主要部分。•线程状态–新线程态–可运行态–运行中状态–等待、阻塞、睡眠状态–死亡态•线程优先级89.3.4线程状态•新建状态、初始化状态:–线程对象已经被创建,但是还没有被启动时的状态。这段时间就是在我们调用new命令之后,调用start()方法之前。•可运行状态、就绪状态:–在我们调用了线程的start()方法之后线程所处的状态。处于RUNNABLE状态的线程在JAVA虚拟机(JVM)上是运行着的,但是它可能还正在等待操作系统分配给它相应的运行资源以得以运行。•运行状态–当线程调度器选择一个线程作为当前执行进程时,该线程就处于运行状态99.3.4线程状态•等待、阻塞、睡眠状态–当以下事件发生时,线程进入非运行态。①suspend()方法被调用;②sleep()方法被调用;③线程使用wait()来等待条件变量;④线程处于I/O等待•DEAD(死亡状态):–当run()方法返回,或别的线程调用stop()方法,线程进入死亡态10线程的执行特性•一个线程必须处于如下五种可能的状态之一:–初始态/新状态–Runnable–运行中状态:–阻塞/NonRunnable–死状态11129.3.5线程控制基本方法方法功能run()线程的执行逻辑start()启动线程isAlive()判断线程是否还“活”着,即线程是否还未终止。getPriority()获得线程的优先级数值setPriority()设置线程的优先级数值yield()暂定线程的执行,允许其它线程竞争CPU,常用于具有同等优先级的线程之间的竞争,适用于不支持时间分片的操作系统之间的线程处理Thread.sleep()将当前线程睡眠指定毫秒数,sleep并不释放锁stop()杀死一个线程,但是通常通过线程内的循环条件来结束一个线程。join()主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。wait()当前线程进入对象的waitpool。notify()/notifyAll()唤醒对象的waitpool中的一个/所有等待线程。13线程状态转换149.3.6线程状态转换publicclassTestThreadStatusextendsThread{//构造函数publicTestThreadStatus(Stringname){super(name);}publicvoidrun(){try{System.out.print(Thread.currentThread().getName());System.out.println(将进入暂停状态。现在时间:+newDate());Thread.sleep(2000);System.out.print(Thread.currentThread().getName()+的状态:);System.out.print(Thread.currentThread().getState());System.out.println(现在时间:+newDate());}catch(InterruptedExceptione){e.printStackTrace();}}}sleep():非运行状态获得运行状态//main方法启动线程publicstaticvoidmain(Stringargs[]){Threadt1=newTestThreadStatus(线程);t1.start();}运行结果:线程将进入暂停状态。现在时间:WedDec0208:40:16CST2009线程的状态:RUNNABLE现在时间:WedDec0208:40:18CST200915publicclassCounterThreadextendsThread{privateintresult;publicCounterThread(Stringname){super(name);}publicintgetResult(){returnresult;}publicvoidrun(){try{Thread.sleep(3000);System.out.println(Thread.currentThread().getName()+被阻塞了3000ms);}catch(InterruptedExceptionex){System.out.println(ex.getMessage());}result=5;}}9.3.7加入线程(join方法)16publicclassTestThreadJoin{publicstaticvoidmain(String[]args){System.out.println(现在的线程是:+Thread.currentThread().getName());longstart=System.currentTimeMillis();System.out.println(开始时间:+start);CounterThreadct1=newCounterThread(线程1);CounterThreadct2=newCounterThread(线程2);ct1.start();ct2.start();longend=System.currentTimeMillis();System.out.println(结束时间:+start);System.out.println(join花费时间:+(end-start)+ms);intresult=ct1.getResult()+ct2.getResult();System.out.println(计算结果:+result);}}线程1启动线程2启动运行结果:现在的线程是:main开始时间:1259717049841结束时间:1259717049841join花费时间:0ms计算结果:0线程1被阻塞了3000ms线程2被阻塞了3000ms加入jion()方法publicclassTestThreadJoin{publicstaticvoidmain(String[]args){System.out.println(现在的线程是:+Thread.currentThread().getName());longstart=System.currentTimeMillis();System.out.println(开始时间:+start);CounterThreadct1=newCounterThread(线程1);CounterThreadct2=newCounterThread(线程2);ct1.start();try{ct1.join();}catch(InterruptedExceptione){System.out.println(e.getMessage());}ct2.start();try{ct2.join();}catch(InterruptedExceptione){System.out.println(e.getMessage());}longend=System.currentTimeMillis();System.out.println(结束时间:+start);System.out.println(join花费时间:+(end-start)+ms);intresult=ct1.getResult()+ct2.getResult();System.out.println(计算结果:+result);}}Thread.join()让当前线程block住,等thread执行完之后,再继续执行。必须等2个线程都执行完才能汇总,那么这时候在主线程里面让2个线程join,最后计算结果既可运行结果:现在的线程是:main开始时间:1259717860458线程1被阻塞了3000ms线程2被阻塞了3000ms结束时间:1259717860458join花