马士兵J2SE第九章线程个人学习笔记.docx
- 文档编号:16172900
- 上传时间:2023-07-11
- 格式:DOCX
- 页数:22
- 大小:1.20MB
马士兵J2SE第九章线程个人学习笔记.docx
《马士兵J2SE第九章线程个人学习笔记.docx》由会员分享,可在线阅读,更多相关《马士兵J2SE第九章线程个人学习笔记.docx(22页珍藏版)》请在冰点文库上搜索。
马士兵J2SE第九章线程个人学习笔记
第九章Java多线程机制
线程基本概念Runnable线程类接口
线程创建和启动
线程的调度好优先级
线程的状态控制sleepjoinyield
线程同步synchronizedwaitnotify/notifyAll
一、线程基本概:
1进程:
一个独立程序的每一次运行称为一个进程。
执行进程是指进程里面主线程mian方法开始执行了(静态概念)。
机器上运行的都是线程
2线程是一个程序不同的执行路径是一个程序内部的顺序控制流)
main方法:
一个主线程,主分支
3一个时间点上一个CPU只能有一个线程执行
进程与线程区别
每个进程都有独立的代码和数据空间,进程间的切换会有很大开销。
线程可以看成轻量级的进程同一类线程共享代码和数据空间,每个线程有独立的运行栈个程序计数器,线程切换开销小。
多线程:
在操作系统中能同时运行多个任务(程序)。
多线程:
在同一个应用程序中有多个顺序流同时执行。
二、线程的创建和启动
1实现Runnable接口(常用)
设计一个实现Runable接口的类,根据需要重写run方法;
建立该类的对象,以此对象为参数建立Thread类的对象;
调用Thread类对象start方法启动线程,将执行权转交到run方法。
2继承Thread类
定义一个从Thread类继承的子类并重写其run方法
然后生成该类的对象,调用Thread类对象start方法启动线程
说明:
Runnable接口java.lang.Runnable
–Java多线程机制的一个重要部分,实际上它只有一个run()方法
–Thread类实现了Runnable接口,相对于Thread类,它更适合于多个线程处理同一资源
–实现Runnable接口的类的对象可以用来创建线程,这时start方法启动此线程就会在此线程上运行run()方法
–在编写复杂程序时相关的类可能已经继承了某个基类,而Java不支持多继承,在这种情况下,便需要通过实现Runnable接口来生成多线程
Thread类java.lang.Thread
–在Java程序中创建多线程的方法之一是继承Thread类
–封装了Java程序中一个线程对象需要拥有的属性和方法
–从Thread类派生一个子类,并创建这个子类的对象,就可以产生一个新的线程。
这个子类应该重写Thread类的run方法,在run方法中写入需要在新线程中执行的语句段。
这个子类的对象需要调用start方法来启动,新线程将自动进入run方法。
原线程将同时继续往下执行
–Thread类直接继承了Object类,并实现了Runnable接口。
它位于java.lang包中,因而程序开头不用import任何包就可直接使用
例子:
Thread\TestThread1.java开始使用Eclipse
1实现Runnable接口(多线程程序交替执行.多态(接口,常用))
packageThread;
publicclassTestThread1{
publicstaticvoidmain(Stringargs[]){
Runnerr=newRunner();
Threadt=newThread(r);//主线程;
t.start();//启动分支线程
for(inti=0;i<100;i++){
System.out.println("MainThread:
----"+i);
}
}
}
classRunnerimplementsRunnable{
publicvoidrun(){//线程运行体;
for(inti=0;i<100;i++){
System.out.println("Runner1:
"+i);
}
}
}
2一般程序先执行子线程,再执行主线程(方法调用)
packageThread;
publicclassTestThread1_1{
publicstaticvoidmain(Stringargs[]){
Runner1r=newRunner1();
r.run();
for(inti=0;i<100;i++){
System.out.println("MainThread:
------"+i);
}
}
}
classRunner1implementsRunnable{
publicvoidrun(){
for(inti=0;i<100;i++){
System.out.println("Runner1:
"+i);
}
}
}
3继承Thread类(继承,不常用)
packageThread;
publicclassTestThread1_2{
publicstaticvoidmain(Stringarg[]){
Runner1_2r=newRunner1_2();
r.start();
for(inti=0;i<=100;i++){
System.out.println("MainThread:
!
!
!
!
"+i);
}
}
}
classRunner1_2extendsThread{
publicvoidrun(){
for(inti=0;i<=100;i++){
System.out.println("Runner2:
!
!
!
!
"+i);
}
}
}
2010-4-221:
04:
16–2010-4-1416:
28:
59
三、线程状态转换
四、线程控制基本方法
Sleep/Join/Yield方法Sleep/Join(需要捕获异常)
例子1Thread/TestInterrupt.Java(线程结束的方式)
packageThread;
importjava.util.*;
publicclassTestInterrupt{
publicstaticvoidmain(Stringarg[]){
MyThreadthread=newMyThread();
thread.start();
try{Thread.sleep(10000);}//主线程睡眠…
catch(InterruptedExceptione){}
thread.interrupt();//中断线程。
}
}
classMyThreadextendsThread{
booleanflag=true;
publicvoidrun(){//重写的方法不能抛出不必被重写方法不同的方法,此处不能写throwsInterruptedException
while(flag){
System.out.println("----"+newDate()+"----");
try{
sleep(1000);
}
catch(InterruptedExceptione){//捕获抛出的异常
return;//停止
}
}
}
}
例子2Thread/TestJoin.Java(线程合并方式)
packageThread;
publicclassTestJoin{
publicstaticvoidmain(String[]args){
MyThread2t1=newMyThread2("abcde");
t1.start();//启动分支线程
try{
t1.join();//把T1分支线程合并到当前线程
}catch(InterruptedExceptione){}
for(inti=1;i<=10;i++){
System.out.println("iammainthread");
}
}
}
classMyThread2extendsThread{
MyThread2(Strings){
super(s);
}
publicvoidrun(){
for(inti=1;i<=10;i++){
System.out.println("iam"+getName());
try{
sleep(1000);
}catch(InterruptedExceptione){
return;
}
}
}
}
例子3Thread/TestYield.Java(让出Cup)
packageThread;
publicclassTestYield{
publicstaticvoidmain(String[]args){
MyThread3t1=newMyThread3("t1");
MyThread3t2=newMyThread3("t2");
t1.start();t2.start();
}
}
classMyThread3extendsThread{
MyThread3(Strings){super(s);}
publicvoidrun(){
for(inti=1;i<=100;i++){
System.out.println(getName()+":
"+i);
if(i%10==0){
yield();
}
}
}
}
五、线程优先级Priority
例子Thread/TestPriority.Java
packageThread;
publicclassTestPriority{
publicstaticvoidmain(String[]args){
Threadt1=newThread(newT1());
Threadt2=newThread(newT2());
t1.setPriority(Thread.NORM_PRIORITY+3);//提高优先级
t1.start();
t2.start();
}
}
classT1implementsRunnable{
publicvoidrun(){
for(inti=0;i<1000;i++){
System.out.println("T1:
"+i);
}
}
}
classT2implementsRunnable{
publicvoidrun(){
for(inti=0;i<1000;i++){
System.out.println("------T2:
"+i);
}
}
}
2010年4月14日21:
40:
41–2010-4-1516:
23:
44
六、例子TestThread2-6
TestThread2一个线程类可以启动两个线程
packageThread;
publicclassTestThread2{//一个线程类可以启动两个线程
publicstaticvoidmain(Stringargs[]){
Runner2r=newRunner2();
Threadt1=newThread(r);
Threadt2=newThread(r);
t1.start();
t2.start();
}
}
classRunner2implementsRunnable{
publicvoidrun(){
for(inti=0;i<30;i++){
System.out.println("No."+i);
}
}
}
正常停止线程TestThread4
packageThread;
publicclassTestThread4{//怎么正常停止线程
publicstaticvoidmain(Stringargs[]){
Runner4r=newRunner4();
Threadt=newThread(r);
t.start();
for(inti=0;i<100000;i++){
if(i%10000==0&i>0)
System.out.println("inthreadmaini="+i);
}
System.out.println("Threadmainisover");
r.shutDown();
//t.stop();
}
}
classRunner4implementsRunnable{
privatebooleanflag=true;
publicvoidrun(){
inti=0;
while(flag==true){
System.out.print(""+i++);
}
}
publicvoidshutDown(){
flag=false;
}
}
TestThread6isAlive
packageThread;
publicclassTestThread6{
publicstaticvoidmain(Stringargs[]){
Threadt=newRunner6();
t.start();
for(inti=0;i<50;i++){
System.out.println("MainThread:
"+i);
}
}
}
classRunner6extendsThread{
publicvoidrun(){
System.out.println(Thread.currentThread().isAlive());
for(inti=0;i<50;i++){
System.out.println("SubThread:
"+i);
}
}
}
七、线程同步
引入:
两人同时取同一账户的钱两个线程访问同一资源,进程之间协调的问题
解决:
在进程访问独占资源时先锁定再访问synchronized最好只锁定一个对象
加锁过程中:
一个方法做了同步(加锁)另一个方法没有做同步,别的线程可以访问没做同步的方法,并且能影响已经同步的方法,要保护需要的同步的对象,必须对要访问的对象所有方法要仔细考虑加不加同步,加同步效率变低,不加同步有可能产生数据不一致的后果
读写两方法,写的方法加锁。
两个方法都改了同一个值,两个方法都应该加同步
TsetSync.java
packageThread;
publicclassTestSyncimplementsRunnable{
Timertimer=newTimer();
publicstaticvoidmain(String[]args){
TestSynctest=newTestSync();
Threadt1=newThread(test);
Threadt2=newThread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
publicvoidrun(){
timer.add(Thread.currentThread().getName());//拿到当前线程的名字
}
}
classTimer{
privatestaticintnum=0;
publicvoidadd(Stringname){
//publicsynchronizedvoidadd(Stringname){//synchronized"锁定"关键字
//synchronized(this){//锁定
num++;
try{Thread.sleep
(1);}//让线程睡眠,给另一个线程执行的机会,更容易看到xia
catch(InterruptedExceptione){}
System.out.println(name+",你是第"+num+"个使用timer的线程");
//}
}
}
t2,你是第2个使用timer的线程
t1,你是第2个使用timer的线程
t2
问题出现在线程执行方法时被另一个线程打断了.
执行:
num++;
.....
System.out.println(name+",你是第"+num+"个使用timer的线程");
两句话时被另个进程打断
死锁
07_线程同步_3.avi
Thread/TestDeadLock.java
两个线程锁定了互斥的对象
packageThread;
//一个线程类模拟两个线程。
用flag区分
publicclassTestDeadLockimplementsRunnable{
publicintflag=1;
staticObjecto1=newObject(),o2=newObject();
publicvoidrun(){
System.out.println("flag="+flag);
if(flag==1){
synchronized(o1){//锁定o1
try{
Thread.sleep(500);
}catch(Exceptione){
e.printStackTrace();
}
synchronized(o2){//锁定o2
System.out.println("1");
}
}
}
if(flag==0){
synchronized(o2){//锁定o2
try{
Thread.sleep(500);
}catch(Exceptione){
e.printStackTrace();
}
synchronized(o1){//锁定o1
System.out.println("0");
}
}
}
}
publicstaticvoidmain(String[]args){
TestDeadLocktd1=newTestDeadLock();
TestDeadLocktd2=newTestDeadLock();
td1.flag=1;
td2.flag=0;
Threadt1=newThread(td1);
Threadt2=newThread(td2);
t1.start();
t2.start();
}
}
一道面试题:
08_线程同步_4.Avi.当m1()方法执行的过程中,另外的线程能执行m2()
packageThread;
publicclassTTimplementsRunnable{
intb=100;
publicsynchronizedvoidm1()throwsException{
b=1000;
Thread.sleep(5000);
System.out.println("b="+b);
}
publicvoidm2(){
System.out.println(b);
}
publicvoidrun(){
try{
m1();
}catch(Exceptione){
e.printStackTrace();
}
}
publicstaticvoidmain(String[]args)throwsException{
TTtt=newTT();
Threadt=newThread(tt);
t.start();
Thread.sleep(1000);
tt.m2();
}
}
结果:
1000
b=1000
八、生产者消费者问题11_线程同步_7_生产者消费者问题.avi
XXX.wait()让当前访问这个线程等待,此时这个线程的锁不存在了
XXXX.notify()唤醒在此对象监视器上等待的单个线程。
一个wait()对应一个notify()
packageThread;
publicclassProducerConsumer{
publicstaticvoidmain(String[]args){
SyncStackss=newSyncStack();
Producerp=newProducer(ss);
Consumerc=newConsumer(ss);
newThread(p).start();
newThread(p).start();
newThread(p).start();
newThread(c).start();
}
}
classWoTou{
intid;
WoTou(intid){
this.id=id;
}
publicStringtoString(){
return"WoTou:
"+id;
}
}
classSyncStack{
intindex=0;
WoTou[]arrWT=newWoTou[6];
publicsynchronizedvoidpush(WoTouwt){
while(index==arrWT.length){
try{
this.wait();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
this.notifyAll();//唤醒
arrWT[index]=wt;
index++;
}
publicsynchronizedWoToupop(){
wh
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 士兵 J2SE 第九 线程 个人 学习 笔记