孙卫琴《Java面向对象编程》配套PPT--java_base4_thread.ppt

上传人:qwe****56 文档编号:70013778 上传时间:2023-01-14 格式:PPT 页数:38 大小:317.50KB
返回 下载 相关 举报
孙卫琴《Java面向对象编程》配套PPT--java_base4_thread.ppt_第1页
第1页 / 共38页
孙卫琴《Java面向对象编程》配套PPT--java_base4_thread.ppt_第2页
第2页 / 共38页
点击查看更多>>
资源描述

《孙卫琴《Java面向对象编程》配套PPT--java_base4_thread.ppt》由会员分享,可在线阅读,更多相关《孙卫琴《Java面向对象编程》配套PPT--java_base4_thread.ppt(38页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、第第6课课 多线程多线程n线程的概念n创建和启动线程n线程的调度n多个线程的同步n线程之间的通信 参见Java面向对象编程的13章线程的概念n进程是指运行中的应用程序,每一个进程都有自己独立的内存空间。对一个应用程序可以同时启动多个进程。例如每次执行JDK的java.exe程序,就启动了一个独立的Java虚拟机进程,该进程的任务是解析并执行Java程序代码。n线程是指进程中的一个执行流程,有时也称为执行情景。一个进程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。当进程内的多个线程同时运行,这种运行方式称为并发运行。主线程n每当用java命令启动一个Jav

2、a虚拟机进程,Java虚拟机就会创建一个主线程,该线程从程序入口main()方法开始执行。public class Sample public void method1(String str)System.out.println(str);public void method2(String str)method1(str);public static void main(String args)Sample s=new Sample();s.method2(hello);main()方法method1()方法method2()方法主线程的方法调用栈线程的创建和启动线程的创建和启动(1)定义一

3、个Thread类的子类,覆盖Thread类的run()方法,然后创建该子类的实例。参见MyThread.java(2)定义一个实现Runnable接口的类,实现它的run()方法,然后将这个类的实例作为Thread的构造方法的参数,创建Thread类的实例。参见MyRunnable.java(3)调用start()方法启动线程。比如,MyThread t=new MyThread();t.start();创建Thread类的子类public class MyThread extends Thread public void run()for(int a=0;a50;a+)tryThread.s

4、leep(100);catch(Exception e)System.out.println(Thread.currentThread().getName()+a);public static void main(String args)MyThread t1=new MyThread();MyThread t2=new MyThread();t1.start();t2.start();区分主线程和用户定义的线程public class MyThread extends Thread public void run()for(int a=0;a50;a+)tryThread.sleep(100

5、);catch(Exception e)System.out.println(Thread.currentThread().getName()+a);public static void main(String args)MyThread t1=new MyThread();t1.start();t1.run();实现Runnable接口public class MyRunnable implements Runnable int a=0;/实例变量 public void run()for(a=0;a10;a+)tryThread.sleep(100);catch(Exception e)S

6、ystem.out.println(Thread.currentThread().getName()+a);public static void main(String args)MyRunnable mr=new MyRunnable();Thread t1=new Thread(mr);/Thread(Runnable r)Thread t2=new Thread(mr);t1.start();t2.start();实现Runnable接口public static void main(String args)MyRunnable mr=new MyRunnable();Thread t1

7、=new Thread(mr);Thread t2=new Thread(mr);t1.start();t2.start();public static void main(String args)MyRunnable mr1=new MyRunnable();MyRunnable mr2=new MyRunnable();Thread t1=new Thread(mr1);Thread t2=new Thread(mr2);t1.start();t2.start();线程状态转换 线程状态转换Stack1对象push()pop()getName()producer1consumer1prod

8、ucer2producer3runningblockedrunnableblockedStack2对象push()pop()getName()producer4consumer2runnableblocked线程调度 因为Java线程的调度不一定是分时的,所以你必须确保你的代码中的线程会不时地给另外一个线程运行的机会。有三种方法可以做到一点:n让处于运行状态的线程调用Thread.sleep()方法。n让处于运行状态的线程调用Thread.yield()方法。n让处于运行状态的线程调用另一个线程的join()方法。线程睡眠:Thread.sleep()方法public class MyThre

9、ad extends Thread public void run()for(int a=0;a50;a+)tryThread.sleep(100);catch(InterruptedException e)System.out.println(Thread.currentThread().getName()+a);public static void main(String args)MyThread t1=new MyThread();MyThread t2=new MyThread();t1.start();t2.start();线程让步:Thead.yield()方法public cl

10、ass MyThread extends Thread public void run()for(int a=0;a50;a+)yield();System.out.println(Thread.currentThread().getName()+a);public static void main(String args)MyThread t1=new MyThread();MyThread t2=new MyThread();t1.start();t2.start();等待其他线程结束:等待其他线程结束:join()public class Machine extends Thread p

11、ublic void run()for(int a=0;a10;a+)System.out.println(getName()+:+a);public static void main(String args)throws Exception Machine machine=new Machine();machine.setName(m1);machine.start();System.out.println(main:join machine);machine.join();/主线程等待machine线程运行结束 System.out.println(main:end);共享资源的竞争n当多

12、个线程共享一些数据,它们的操作会竞争共享资源,这会导致一些意想不到的错误。n以一个生产者(Producer),消费者(Consumer)为例,生产者向一个堆栈(SyncStack)中加入产品,字符消费者向同一个堆栈中取出产品。nSyncTest类:提供程序入口main()方法,负责创建生产者和消费者线n程,并且启动这些线程。nProducer类:生产者线程,不断向堆栈中加入产品。nConsumer类:消费者线程,不断向堆栈中取出产品。nStack类:堆栈,允许从堆栈中取出或加入产品。参见mythreadproblemSyncTest.java堆栈Stack.javaclass Stack pr

13、ivate String name;private String buffer=new String100;int point=-1;public String pop()String goods=bufferpoint;bufferpoint=null;Thread.yield();point-;return goods;public void push(String goods)point+;Thread.yield();bufferpoint=goods;buffer0buffer1buffer2buffer3push()pop()point生产者线程class Producer ext

14、ends Thread private Stack theStack;public Producer(Stack s,String name)super(name);theStack=s;start();/启动自身生产者线程 public void run()String goods;for(int i=0;i 200;i+)goods=goods+(theStack.getPoint()+1);theStack.push(goods);System.out.println(getName()+:push +goods+to+theStack.getName();yield();buffer0

15、=goods0buffer1=goods1buffer2=goods2buffer3=goods3point生产者线程消费者线程class Consumer extends Thread private Stack theStack;public Consumer(Stack s,String name)super(name);theStack=s;start();/启动自身消费者线程 public void run()String goods;for(int i=0;i 200;i+)goods=theStack.pop();System.out.println(getName()+:pop

16、 +goods+from+theStack.getName();yield();buffer0=goods0buffer1=goods1buffer2=goods2buffer3=goods3point消费者线程创建生产者和消费者线创建生产者和消费者线程程public class SyncTest public static void main(String args)Stack stack=new Stack(stack1);Producer producer1=new Producer(stack,producer1);Consumer consumer1=new Consumer(sta

17、ck,consumer1);堆栈生产者消费者共享资源的竞争 打印结果:producer1:push goods0 to stack1consumer1:pop null from stack1producer1:push goods0 to stack1线程的同步线程的同步n同步是一种保证共享资源完整性的手段n具体作法是在代表原子操作的程序代码前加上synchronized标记,这样的代码被称为同步代码块。public String pop()synchronized(this)String goods=bufferpoint;bufferpoint=null;Thread.yield();p

18、oint-;return goods;public synchronized String pop()String goods=bufferpoint;bufferpoint=null;Thread.yield();point-;return goods;对操纵堆栈的方法同步class Stack public synchronized int getPoint()return point;public synchronized String pop()public synchronized void push(String goods)对操纵堆栈的方法同步每个Java对象都有且只有一个同步锁

19、,在任何时刻,最多只允许一个线程拥有这把锁。当消费者线程试图执行带有synchronized标记的代码块pop()方法,消费者线程必须首先获得Stack对象的锁。在以下两种情况,消费者线程有着不同的命运:假如这个锁已经被其他线程占用,Java虚拟机就会把这个消费者线程放到Stack对象的锁池中,消费者线程进入阻塞状态。在Stack对象的锁池中可能会有许多等待锁的线程。等到其他线程释放了锁,Java虚拟机会从锁池中随机的取出一个线程,使这个线程拥有锁,并且转到就绪状态。假如这个锁没有被其他线程占用,消费者线程就会获得这把锁,开始执行同步代码块。一般情况下,消费者线程只有执行完同步代码块,才会释放

20、锁,使得其他线程能够获得锁,当然也有一些例外情况。比如当线程执行同步代码块时出现中断或异常而跳出synchronized代码块,锁也会自动释放。线程的同步的特点线程的同步的特点n一把锁可以锁住多个同步代码块n锁对非同步代码块无效n当一个线程进入同步代码块,并不意味着指定代码必须以不中断的方式运行。n当一个线程占有了某个对象的锁,其他需要获得这个锁的线程就进入锁池中,等待获得锁的机会。线程的同步的特点线程的同步的特点public class SyncTest public static void main(String args)Stack stack1=new Stack(stack1);Pr

21、oducer producer1=new Producer(stack1,producer1);Producer producer2=new Producer(stack1,producer2);Producer producer3=new Producer(stack1,producer3);Consumer consumer1=new Consumer(stack1,consumer1);Stack stack2=new Stack(stack2);Producer producer4=new Producer(stack2,producer4);Consumer consumer2=ne

22、w Consumer(stack2,consumer2);线程的同步的特点线程的同步的特点Stack1对象push()pop()getName()producer1consumer1producer2producer3runningblockedrunnableblockedStack2对象push()pop()getName()producer4consumer2runnableblocked死锁n当一个线程等待由另一个线程持有的锁,而后者正在等待已被第一个线程持有的锁时,就会发生死锁。nJava不监测也不试图避免这种情况。因而保证不发生死锁就成了程序员的责任。n参见DeadLockTest

23、.java死锁class Operator implements Runnable Operator anotherOperator;synchronized public void methodA()System.out.println(Thread.currentThread().getName()+:begin methodA);tryThread.sleep(200);catch(Exception e)System.out.println(Thread.currentThread().getName()+:call another methodA);anotherOperator.m

24、ethodA();System.out.println(Thread.currentThread().getName()+:end methodA);public void run()methodA();死锁public class DeadLockTest public static void main(String args)Operator o1=new Operator();Operator o2=new Operator();o1.anotherOperator=o2;o2.anotherOperator=o1;Thread t1=new Thread(o1);Thread t2=n

25、ew Thread(o2);t1.start();t2.start();Operator1methodA()t1Operator2methodA()t2线程通信线程通信n不同的线程执行不同的任务,如果这些任务有某种联系,线程之间必须能够通信,协调完成工作。例如生产者和消费者共同操作堆栈,当堆栈为空时,消费者无法取出产品,应该先通知生产者向堆栈中加入产品。当堆栈已满时,生产者无法继续加入产品,应该先通知消费者从堆栈中取出产品。njava.lang.Object类中提供了两个用于线程通信的方法:nwait():执行该方法的线程释放对象的锁,Java虚拟机把该线程放到该对象的等待池中。该线程等待其他

26、线程将它唤醒。nnotify():执行该方法的线程唤醒在对象的等待池中等待的一个线程。Java虚拟机从对象的等待池中随机的选择一个线程,把它转到对象的锁池中。线程通信线程通信n假定线程t1和线程t2共同操纵一个对象s,这两个线程可以通过对象s的wait()和notify()方法来进行的通信。S 对象method1()t1t2method2()生产者与消费者线程通信class Stack public synchronized String pop()this.notifyAll();while(point=-1)System.out.println(Thread.currentThread()

27、.getName()+:wait);try this.wait();catch(InterruptedException e)throw new RuntimeException(e);String goods=bufferpoint;bufferpoint=null;Thread.yield();point-;return goods;public synchronized void push(String goods)参见mythreadnewproblemSyncTest.java生产者与消费者线程通信class Stack public synchronized void push(S

28、tring goods)this.notifyAll();while(point=buffer.length-1)System.out.println(Thread.currentThread().getName()+:wait);try this.wait();catch(InterruptedException e)throw new RuntimeException(e);point+;Thread.yield();bufferpoint=goods;生产者与消费者线程通信public class SyncTest public static void main(String args)

29、Stack stack1=new Stack(stack1);Producer producer1=new Producer(stack1,producer1);Consumer consumer1=new Consumer(stack1,consumer1);Consumer consumer2=new Consumer(stack1,consumer2);生产者与消费者线程通信n对于stack1,同时有两个消费者取出产品,只有一个生产者加入产品,因此有可能导致消费者取产品时堆栈为空的情况。以下是consumer2线程取产品时可能出现的流程。n n(1)执行this.notifyAll()方

30、法,此时this引用的stack1对象的等待池中没有任何线程,因此该方法什么也不做。n(2)由于point为-1,因此执行this.wait()方法,consumer2线程释放stack1对象的锁,并且进入stack1对象的等待池。n(3)producer1线程获得stack1对象的锁,开始执行push()方法。n(4)producer1线程首先执行this.notifyAll()方法,此时this引用的stack1对象的等待池中有一个consumer2线程,因此把这个线程转到stack1对象的锁池。n(5)producer1线程判断point不为buffer.length-1,无需执行thi

31、s.wait()方法,producer1线程向堆栈中加入一个产品,然后退出push()方法,并且释放锁。n(6)在stack1对象的锁池中的consumer2线程获得了锁,转到就绪状态,只要获得了CPU,就能继续执行pop()方法。终止线程n当线程执行完run()方法,它将自然终止运行。n Thread有一个stop()方法,可以强制结束线程,但这种方法是不安全的。因此,在JDK1.2开始的版本中,stop()方法已经被废弃。n实际编程中,一般是定义一个标志变量,然后通过程序来改变标志变量的值,从而控制线程从run()方法中自然退出。参见MyThreadStop.java 终止线程public

32、 class MyThreadStop extends Thread int a;boolean flag=false;public void run()while(!flag)System.out.println(a+);public void setFlag(boolean _flag)flag=_flag;public static void main(String args)MyThreadStop t=new MyThreadStop();t.start();try Thread.sleep(1000);catch(Exception e)t.setFlag(true);Thread

33、类的方法类的方法ncurrentThread()返回当前运行的Thread对象。nstart()启动一个线程。nrun()线程体,由start()方法调用,当run()方法返回时,当前的线程结束。nstop()使调用它的线程立即停止执行。nsleep(int n)使线程睡眠n毫秒,n毫秒后,线程可以再次运行。nsuspend()使线程挂起,暂停运行。nresume()恢复挂起的线程,使其处于可运行状态(Runnable)。nyield()将CPU控制权主动移交到下一个可运行线程。nsetPriority()设置线程优先级。ngetPriority()返回线程优先级。nsetName()设置线程的名字。ngetName()返回该线程的名字。nisAlive()如果线程已被启动并且未被终止,那么isAlive()返回true。如果返回false,则该线程是新创建或是已被终止的。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁