Java线程及多线程技术及应用Word文档格式.docx
《Java线程及多线程技术及应用Word文档格式.docx》由会员分享,可在线阅读,更多相关《Java线程及多线程技术及应用Word文档格式.docx(36页珍藏版)》请在冰豆网上搜索。
publicstaticvoidmain(Stringargs)/main方法测试线程的创建与启动MyThreadmyThread=newMyThread();
/实例化MyThread的对象myThread.start();
/调用myThread对象的start方法启动一个线程3、利用实现Runable接口创建线程的示例packagecom.px1987.j2se.thread.base;
/*通过Runable接口实现多线程定义MyRunable类实现Runnable接口,并实现接口中的run方法。
*/publicclassMyRunableimplementsRunnablepublicvoidrun()while(true)System.out.println(invokeMyRunablerunmethod);
publicstaticvoidmain(Stringargs)/main方法测试线程的创建与启动/建立MyRunable类的对象,以此对象为参数建立Thread类的对象Threadthread=newThread(newMyRunable();
thread.start();
/调用thread对象的start方法启动一个线程3线程的状态控制线程的状态控制1、新建状态用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。
处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable)。
2、就绪状态处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列,等待系统为其分配CPU。
等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调度”。
一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。
3、死亡状态死亡状态是线程生命周期中的最后一个阶段。
线程死亡的原因有两个:
一个是正常运行的线程完成了它的全部工作;
另一个是线程被强制性地终止,如通过执行stop或destroy方法来终止一个线程。
Methodstop()&
destroy()intheclassThreadisdeprecated。
当一个线程进入死亡状态以后,就不能再回到其它状态了。
让一个Thread对象重新执行一次的唯一方法,就是重新产生一个Thread对象。
4、体现线程状态转变的代码示例packagecom.px1987.j2se.thread.base;
publicclassMyRunable1implementsRunnablepublicvoidrun()while(true)System.out.println(invokeMyRunablerunmethod);
publicstaticvoidmain(Stringargs)Threadthread=newThread(newMyRunable();
/新生状态thread.start();
/就绪状态,获得CPU后就能运行tryThread.sleep(5000);
catch(InterruptedExceptione)e.printStackTrace();
thread.stop();
/死亡状态通过查API可以看到stop方法和destory方法已经过时了,所以不能再用,那要怎样做才能强制的销毁一个线程呢?
1、在run方法中执行return线程同样结束2、可以在while循环的条件中设定一个标志位,当它等于false的时候,while循环就不在运行,这样线程也就结束了。
代码为实现的代码示例:
packagecom.px1987.j2se.thread.StateControl;
publicclassMyRunable2implementsRunnableprivatebooleanisStop;
/线程是否停止的标志位publicvoidrun()while(!
isStop)System.out.println(invokeMyRunablerunmethod);
publicvoidstop()/终止线程isStop=true;
publicstaticvoidmain(Stringargs)MyRunablemyRunable=newMyRunable();
Threadthread=newThread(myRunable);
tryThread.sleep(5000);
myRunable.stop();
/正确的停止线程的方法5、阻塞状态处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。
在阻塞状态的线程不能进入就绪队列。
只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行。
有三种方法可以暂停Threads执行:
(1)sleep方法可以调用Thread的静态方法:
publicstaticvoidsleep(longmillis)throwsInterruptedException使得当前线程休眠(暂时停止执行millis毫秒)。
由于是静态方法,sleep可以由类名直接调用:
Thread.sleep()。
下面为代码示例:
packagecom.px1987.j2se.thread.p5;
importjava.util.Date;
importjava.text.SimpleDateFormat;
classSleepTestimplementsRunnableprivatestaticSimpleDateFormatformat=newSimpleDateFormat(yyyy-MM-ddhh:
mm:
ss);
publicvoidrun()System.out.println(childthreadbegin);
inti=0;
while(i+5)System.out.println(format.format(newDate();
System.out.println(childthreaddeadat:
+format.format(newDate();
publicstaticvoidmain(Stringargs)Runnabler=newSleepTest();
Threadthread=newThread(r);
tryThread.sleep(20000);
thread.interrupt();
System.out.println(mainmethoddead!
);
该程序的运行结果如下:
childthreadbegin2009-02-0604:
50:
292009-02-0604:
342009-02-0604:
392009-02-0604:
44mainmethoddead!
java.lang.InterruptedException:
sleepinterruptedatjava.lang.Thread.sleep(NativeMethod)atcom.px1987.j2se.thread.p5.Thread4.run(Thread4.java:
17)atjava.lang.Thread.run(UnknownSource)2009-02-0604:
49childthreaddeadat:
2009-02-0604:
54
(2)yield方法让出CPU的使用权,从运行态直接进入就绪态。
classThread5implementsRunnableprivateStringname;
Thread5(Strings)this.name=s;
publicvoidrun()for(inti=1;
i=50;
i+)System.out.println(name+:
+i);
if(i%10=0)Thread.yield();
publicclassYieldTestpublicstaticvoidmain(Stringargs)Runnabler1=newThread5(S1);
Runnabler2=newThread5(S2);
Threadt1=newThread(r1);
Threadt2=newThread(r2);
t1.start();
t2.start();
tryThread.sleep
(2);
System.out.println(mainmethodover!
该程序的部分运行结果如下:
S1:
20S2:
7S2:
8S2:
9S2:
10S1:
41S1:
42S1:
43S1:
44S1:
45S1:
46S1:
47S1:
48S1:
49S1:
50S2:
11S2:
12(3)join方法当某个(A)线程等待另一个线程(B)执行结束后,才继续执行时,使用join方法。
A的run方法调用b.join()。
下面为代码示例。
packagecom.px1987.j2se.thread.join;
classFatherThreadimplementsRunnablepublicvoidrun()System.out.println(爸爸想抽烟,发现烟抽完了);
System.out.println(爸爸让儿子去买包红塔山);
Threadson=newThread(newSonThread();
son.start();
System.out.println(爸爸等儿子买烟回来);
try/join含义:
等待son线程执行完毕,father线程才继续执行son.join();
catch(InterruptedExceptione)System.out.println(爸爸出门去找儿子跑哪去了);
System.exit
(1);
System.out.println(爸爸高兴的接过烟开始抽,并把零钱给了儿子);
classSonThreadimplementsRunnablepublicvoidrun()Stringtabs=tttttt;
System.out.println(tabs+儿子出门去买烟);
System.out.println(tabs+儿子买烟需要10分钟);
tryfor(inti=0;
i10;
)Thread.sleep(1000);
System.out.println(tabs+儿子出去第+i+分钟);
System.out.println(tabs+儿子买烟回来了);
publicclassJoinTestpublicstaticvoidmain(Stringargs)System.out.println(爸爸和儿子的故事);
Threadfather=newThread(newFatherThread();
father.start();
/try/Thread.sleep(5000);
/catch(InterruptedExceptione)/e.printStackTrace();
/father.interrupt();
爸爸和儿子的故事爸爸想抽烟,发现烟抽完了爸爸让儿子去买包红塔山爸爸等儿子买烟回来儿子出门去买烟儿子买烟需要10分钟儿子出去第1分钟儿子出去第2分钟儿子出去第3分钟儿子出去第4分钟儿子出去第5分钟儿子出去第6分钟儿子出去第7分钟儿子出去第8分钟儿子出去第9分钟儿子出去第10分钟儿子买烟回来了爸爸高兴的接过烟开始抽,并把零钱给了儿子当时间来到儿子出去买烟的时候,Father线程调用interrupt方法就会打断son线程的正常执行,从而father线程也就不必等待son线程执行完毕再行动了,运行结果如下:
爸爸和儿子的故事爸爸想抽烟,发现烟抽完了爸爸让儿子去买包红塔山爸爸等儿子买烟回来儿子出门去买烟儿子买烟需要10分钟儿子出去第1分钟儿子出去第2分钟儿子出去第3分钟儿子出去第4分钟爸爸出门去找儿子跑哪去了4线程的调度和优先级线程的调度和优先级1、线程的基本信息方法功能isAlive()判断线程是否还“活”着,即线程是否还未终止。
getPriority()获得线程的优先级数值setPriority()设置线程的优先级数值setName()给线程一个名字getName()取得线程的名字currentThread()取得当前正在运行的线程对象,也就是取得自己本身2、操作线程的基本信息代码示例packagecom.px1987.j2se.thread.priority;
publicclassThreadInfoTestpublicstaticvoidmain(Stringargc)throwsExceptionRunnabler=newMyThread();
Threadt=newThread(r,Nametest);
t.start();
System.out.println(nameis:
+t.getName();
Thread.currentThread().sleep(5000);
System.out.println(t.isAlive();
System.out.println(over!
classMyThreadimplementsRunnablepublicvoidrun()for(inti=0;
i100;
i+)System.out.println(i);
nameis:
Nametest0123.979899falseover!
3、线程的优先级
(1)优先级(共10级):
它们决定线程执行的先后次序(优先级高者先执行)并可以通过Thread类中的setPriority()和getPriority()方法来改变和获取优先级。
典型的优先级码Thread.MIN_PRIORITY(1级)Thread.MAX_PRIORITY(10级)Thread.NORM_PRIORITY(5级)
(2)调度规则Java是不支持线程时间片轮换的调度模型,而采用的是线程优先级高低的抢占调度模型。
具有高优先级的线程可以抢占低优先级线程运行的机会。
高优先级的线程将始终获得线程执行时间。
但是这也不是绝对的,java线程调度器有可能会调用长期处于等待的线程进行执行,所以不要依靠线程的高优先级抢占模型去完成某些功能。
Java线程调度器支持不同优先级线程的抢先方式,但其本身不支持相同优先级线程的时间片轮换。
但是如果java运行时系统所在的操作系统(如windows2000)支持时间片的轮换,则线程调度器就支持相同优先级线程的时间片轮换。
(3)代码示例packagecom.px1987.j2se.thread.priority;
publicclassThreadPriorityTestpublicstaticvoidmain(Stringargs)Threadt1=newThread(newMyThread2(),t1);
Threadt2=newThread(newMyThread2(),t2);
t1.setPriority
(1);
t2.setPriority(10);
classMyThread2extendsThreadpublicvoidrun()for(inti=0;
i+)System.out.println(Thread.currentThread().getName()+:
yield();
t1:
0t2:
1t2:
2t2:
3t2:
4t2:
5t2:
6t2:
7t2:
8t2:
9t1:
1t1:
2t1:
3t1:
4t1:
5t1:
6t1:
7t1:
8t1:
95线程同步互斥线程同步互斥1、线程同步互斥的一个示例多个线程同时访问或操作同一资源时,很容易出现数据前后不一致的问题。
请看下面的例子:
男孩拿着折子去北京银行海淀分行取钱女孩拿着男孩的银行卡去西单百货疯狂购物男孩走到柜台钱询问帐户余额银行的业务员小姐亲切地告诉他:
您还有10000元!
。
女孩看上了一件时髦的衣裳,准备买下男孩在思考要取多少钱呢?
女孩到收银台准备刷卡消费收银台刷卡机读取银行卡余额为10000元女孩买衣服刷卡消费5000元消费清单打印出来,消费:
5000元余额:
5000元女孩离开商场男孩思考了1毫秒男孩决定取5000元银行的业务员小姐为男孩办理相关业务手续交易完成银行的业务员小姐告诉男孩:
您的余额为5000元。
男孩离开银行男孩帐户中一共有10000元,男孩拿着存折从银行取走5000元,女孩拿着男孩的银行卡购物刷卡消费5000元,最后男孩的帐户里却还剩5000元。
显然这是不正确的,但是为什么会发生这样的情况呢?
我们可以这样分析:
男孩可以看作是一条线程,女孩也可以看作是一条线程,在同一时刻,两个线程都操作了同一个资源,那就是男孩的帐户。
男孩从查看帐户余额到取走现金应该被看作是个原子性操作,是不可再分的,然而当男孩查看完余额正思考取多少钱的时候,女孩购物消费了5000元,也就是说女孩这条线程打断了男孩这条线程所要执行的任务。
所以男孩刚查看完的余额10000元就不正确了,最终导致帐户中少减了5000元。
为了避免这样的事情发生,我们要保证线程同步互斥,所谓同步互斥就是:
并发执行的多个线程在某一时间内只允许一个线程在执行以访问共享数据2、Java中线程互斥的实现机制由多线程带来的性能改善是以可靠性为代价的,所以编程出线程安全的类代码是十分必要的。
当多个线程可以访问共享资源(调用单个对象的属性和方法,对数据进行读、写、修改、删除等操作)时,应保证同时只有一个线程访问共享数据,Java对此提出了有效的解决方案同步锁。
任何线程要进入同步互斥方法(访问共享资源的方法或代码段)时,就必须得到这个共享资源对象的锁,线程进入同步互斥方法后其它线程则不能再进入同步互斥方法,直到拥有共享资源对象锁的线程执行完同步互斥方法释放了锁,下一个线程才能进入同步互斥方法被执行。
Java的这一线程互斥的实现机制可以用一个最通俗的比方来说明:
比如公共卫生间就是一个共享资源,每个人都可以使用,但又不能同时使用,所以卫生间里有一把锁。
一个人进去了,会把门锁上,其他人就不能进去。
当Ta出来的时候,要打开锁,下一个人才能继续使用。
3、利用Synchronized关键字用于修饰同步互斥方法
(1)同步互斥方法publicsynchronizedvoidmethod()/允许访问控制的代码
(2)同步互斥代码块synchronized(syncObject)/允许访问控制的代码(3)锁定整个类publicsynchronizedclassSyncObject由于synchronized块可以针对任意的代码块,且可任意指定上锁的对象,因此灵活性较高。
但要注意:
synchronized可以用来限定一个方法或一小段语句或整个类(该类中的所有方法都是synchronized方法)将访问共享数据的代码设计为synchronized方法由于可以通过private关键字来保证数据对象只能被方法访问,所以只需针对方法提出一套同步锁定机制。
通过synchronized方法来控制对类中的成员变量(共享数据)的访问。
编写线程安全的