资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,Java,多线程,Java,线程模型,理解线程概念,进程的概念,线程的概念,线程与进程的区别和联系,一个进程在其执行过程中,可以产生多个线程。,在进程概念中,每一个进程的内部数据和状态都是完全独立的。但与进程不同的是,同类的多个线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈。,线程是比进程更小的执行单位,是进程内部独立的,有序的指令流。由此,一个进程能包含多个并发执行的线程。线程是一种能够独立运行的子任务。,多线程是一种允许在程序中并发执行彼此间互相独立的多个线程机制。,多个线程的执行是并发的。,多个线程之间的代码是乱序执行的,由此线程调度,同步等问题需要进行特殊处理。,1.,线程的生命周期,线程的,5,种状态及转换方法,新生态,Now Bron,运行态,Running,可运行态,Runnable,阻塞态,Blocked,死亡态,Dead,suspend(),sleep(),wait(),resume(),notify(),start(),yield(),stop(),stop(),stop(),1.,新生状态,当利用,new,运算符创建线程对象实例后,它仅仅作为一个对象实例存在,,JVM,没有为其分配,CPU,时间片等线程运行资源,该线程处于新生状态。,2.,可运行状态,在处于新生状态的线程中调用,start(),方法将线程的状态转换为可运行状态。这时,线程已经得到除,CPU,时间之外的其它系统资源,只等,JVM,的线程调度管理器按照线程的优先级对该线程进行调度,从而使该线程拥有能够获得,CPU,时间片的机会。,3.,运行状态,JVM,的线程调度管理器选中一个可运行状态线程,使其占有,CPU,并转换为运行状态。运行状态的线程执行自己的,run(),方法中的代码,直到调用其他方法而终止、或等待某资源而阻塞或完成任务而死亡。,4.,睡眠状态,处于运行状态的线程在某些情况下,如执行了,sleep(),方法,或等待,I/O,设备等资源,将让出,CPU,并暂时终止自己的运行,进入阻塞状态,也称为不可运行状态。,处于阻塞状态的线程是不可执行的,即使,CPU,空闲,也不能执行。只有当引起阻塞的原因被消除时,线程转入可运行状态,重新进入线程队列中排队等待运行,再次运行时从原来终止处继续运行。,5.,死亡状态,死亡状态是线程生命周期中的最后一个阶段。导致线程死亡的有,2,种情况:一是正常运行的线程完成了它的全部工作,这个任务完成的动作是由,run(),方法实现的;另一个是线程被强制性地终止,如通过执行,stop(),方法来终止一个线程。,可以用,isAlive(),方法测试线程是否已启动。如果,isAlive(),方法返回,false,,表示该线程是新创建或已被终止;如果返回,true,,表示该线程已启动且未被终止,是可运行状态、运行状态或阻塞状态之一,但不能作进一步的分辨。,2.,线程控制,(1) start(),方法,start(),方法对应于启动操作,(2) stop(),方法,stop(),方法终止在任何状态的线程,使之转入到死亡状态,(3) sleep(),方法,sleep(),方法使线程暂停运行一段固定的时间。在休眠时间内,由于线程不能得到,CPU,时间而不运行,指定的时间一过,线程重新进入可运行状态。,public static void sleep(longmillis) throws InterruptedException,public static void sleep(longmillis, intnanos) throws InterruptedException,(4) yield(),方法,yield(),方法使得线程放弃当前分得的,CPU,时间,但是不使线程阻塞,即线程仍处于可运行状态,随时可能再次分得,CPU,时间,(5) wait(),方法,wait(),方法使得当前线程进入阻塞状态,直到被唤醒或等够了,timeout,指定的时间。注意:,wait(),等价于,wait(0),,它使得线程永远等待直到被唤醒为止。,public final void wait(longtimeout) throws InterruptedException,public final void wait(longtimeout, intnanos) throws InterruptedException,public final void wait() throws InterruptedException,(6) notify(),方法和,notifyAll(),方法,notify(),方法和,notifyAll(),方法对应于唤醒操作。,(7) suspend(),方法和,resume(),方法,suspend(),方法和,resume(),方法配套使用,,suspend(),方法使得线程进入阻塞状态,并且不会自动恢复,必须其对应的,resume(),方法被调用,才能使得线程重新进入可执行状态。,(8) interrupt(),方法和,interrupted(),方法,interrupt(),方法为线程设置一个中断标记,以便于,run(),方法运行时使用,isInterrupted(),方法能够检测到,此时,线程在,sleep(),之类的方法中被阻塞时,由,sleep(),方法抛出一个,InterruptedException,异常,然后捕获这个异常以处理超时。,(9) isAlive(),方法,isAlive(),方法用来判断一个线程的,run(),方法是否还在执行,如果是在运行,则返回,true,,否则返回,false,。,3.,线程的创建,在,Java,中创建线程的方法有,2,种:一是通过创建,Thread,类的子类来实现,二是通过实现,Runnable,接口的类来实现。,用继承,Thread,类的子类或通过实现,Runnable,接口的类来创建线程无本质的区别。但是由于,Java,语言不允许多重继承,所以,如果类已经继承了别的类,这样它就不能再继承,Thread,了。这时,就要用,Runnable,接口的方式。,(1)Thread,类与,Runnable,接口,Thread,类用于创建和控制线程。一个线程必须从,run(),方法开始执行,而,run(),方法声明在,java.lang.Runnable,接口中。,Runnable,接口中只声明了一个,run(),方法。任何实现,Runnable,接口的对象都可以作为一个线程的目标对象。,一个线程对象必须实现,run(),方法来完成线程的所有活动,已实现的,run(),方法称为该对象的线程体。,Thread,类在,java.lang,包中定义,,Thread,类的构造方法如下:,(1) Thread (),(2) Thread (Runnabletarget),(3) Thread (Runnabletarget, Stringname),(4) Thread (Stringname),(5) Thread (ThreadGroupgroup, Runnabletarget),(6) Thread (ThreadGroupgroup, Runnabletarget, Stringname),(7) Thread (ThreadGroupgroup, Stringname),任何实现,Runable,接口的对象对可以作为,Thread,类构造方法中的,target,参数,而,Thread,类本身也实现了,Runable,接口。因此,可以有,2,种方式提供,run(),方法来实现多线程。,(2),继承,Thread,类实现多线程,Thread,类是一个具体的类,即不是抽象类,该类封装了线程的行为。要创建一个线程:,Thread,类包含了线程运行所需要的方法,当一个类继承了,Thread,类后就可以在重写父类中的,run,()方法来执行指定的操作。,需要注意的是线程子类的对象需要通过调用自己的,start,()方法让线程执行,,start,()方法会自动调用,run,()方法。,。,例,通过继承,Thread,实现多线程,public class SimpleThread extends Thread,int count= 1, number;,public SimpleThread(int num),number = num;,System.out.println(,创建线程, + number);,public void run(),while(true),System.out.println(,线程, + number + :,计数, + count);,if(+count= 4) return;,public static void main(String args),for(int i = 0; i 3; i+),new SimpleThread(i+1).start();,(3),通过,Runnable,接口实现多线程,用,Runnable,接口创建线程,实现线程的另外一种方法是通过使用,Thread,类的一个构造方法,public Thread(Runnable target),来创建一个新的线程 ,,其中创建参数,target,的类负责实现,Runnable,接口。,Runnable,接口中只有一个,run( ),方法,实现该接口的类必须实现接口中的,run( ),方法,,在其中定义具体操作,然后将实现了,Runnable,接口的类的对象作为参数创建一个,Thread,类的对象,调用该,Thread,类对象的,start( ),方法启动线程。,例,通过实现,Runnable,接口实现多线程,public class,Runnable1,implements Runnable,int k=0;,public Runnable1(int k),this.k = k;,public void,run(),int i = k;,while (i50),System.out.print(i+ );,i+=2;,public static void main (String args) ,Runnable1,r1,= new Runnable1(1); /,创建具有线程体的目标对象,Runnable1,r2,= new Runnable1(2);,Thread t1=new,Thread(r1),; /,以目标对象创建线程,Thread t2=new,Thread(r2),;,t1.start(),;,t2.start(),;,for (int i=0;i40;i+) System.out.print(A );,两种线程实现方式的对比分析,通过继承,Thread,类来实现多线程的编程这种方法简单明了,但是它也有一个很大的缺点,那就是如果相应的多线程处理类已经继承了一个类,便无法再继承,Thread,这个类,所以我们一般情况下采用,Runnable,接口的方法来实现多线程的编程。使用,Runnable,接口的来实现多线程在开发过程中能够在一个类中包容所有的代码,以便封装。但是使用,Runnable,接口的方法的缺点在于如果想创建多个线程并使各个线程执行不同的的代码,就必须创建额外的类,这样的话在某些情况下不如直接用多个类分别继承,Thread,紧凑。,18,线程的优先级,线程的优先级用数字来表示,范围从,1,到,10,,即,Thread.MIN_PRIORITY,到,Thread.MAX_PRIORITY,。一个线程的缺省优先级是,5,,即,Thread.NORM_PRIORITY,。,int getPriority();,void setPriority(int newPriority);,19,class ThreadTest,public static void main( String args ) ,Thread t1 = new MyThread(T1);,t1.setPriority(,Thread.MIN_PRIORITY,);,t1.start( );,Thread t2 = new MyThread(T2);,t2.setPriority(,Thread.MAX_PRIORITY,);,t2.start( );,Thread t3 = new MyThread(T3);,t3.setPriority(,Thread.MAX_PRIORITY,);,t3.start( );,20,class MyThread extends Thread ,String message;,MyThread ( String message ) ,this.message = message;,public void run() ,for ( int i=0; i3; i+ ),System.out.println( message+ +getPriority() );,21,运行结果:,T2 10,T2 10,T2 10,T3 10,T3 10,T3 10,T1 1,T1 1,T1 1,22,注意:并不是在所有系统中运行,Java,程序时都采用时间片策略调度线程,所以一个线程在空闲时应该主动放弃,CPU,,以使其他同优先级和低优先级的线程得到执行。,
展开阅读全文