• / 47
  • 下载费用:10 金币  

第15讲 Java多线程.ppt

关 键 词:
第15讲 Java多线程.ppt
资源描述:
Java多线程,2019/9/30,Java多线程,2,Java多线程,进程与线程概念 创建和启动Java线程 多线程的互斥与同步 线程状态和线程控制 死锁的概念,2019/9/30,Java多线程,3,进程与线程,进程一般是对操作系统而言的。例如,你打开word编辑文档,同时打开outlook收取邮件。我们可以说这时系统内有两个进程在运行。即多个程序几乎在同一时间执行多个任务。 线程一般是对某一程序而言的。如上例,你打开outlook收新邮件的同时,还可以看已下载的邮件,这两件事没有相互干扰,那么我们说此时这一程序中至少有两个线程在运行。即每一个程序在同一时间内执行多个任务。,2019/9/30,Java多线程,4,进程与线程,从逻辑的观点来看,多线程意味着一个程序的多行语句同时执行,但是多线程并不等于多次启动一个程序,操作系统也不会把每个线程当作独立的进程来对待:,2019/9/30,Java多线程,5,进程与线程,两者的粒度不同,是两个不同层次上的概念。进程是由操作系统来管理的,而线程则是在一个程序(进程)内。 (可以看看win2000的任务管理器)不同进程的代码、内部数据和状态都是完全独立的,而一个程序内的多线程是共享同一块内存空间和同一组系统资源,有可能互相影响。线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程的切换比进程切换的负担要小。,2019/9/30,6,多线程,,,2019/9/30,Java多线程,7,多线程的优势,减轻编写交互频繁、涉及面多的程序的困难(如监听网络端口)。程序的吞吐量会得到改善(同时监听多种设备,如网络端口、串口、并口以及其他外设)。有多个处理器的系统,可以并发运行不同的线程(否则,任何时刻只有一个线程在运行)。,2019/9/30,Java多线程,8,线程的调度,调度策略 时间片抢占式:高优先级的线程抢占CPU Java的调度方法 同优先级线程组成先进先出队列,使用时间片策略 对高优先级,使用优先调度的抢占式策略,,1,2,2019/9/30,Java多线程,9,线程,虚拟的CPU,由java.lang.Thread类封装和虚拟CPU来实现。 CPU所执行的代码,传递给Thread类对象。 CPU所处理的数据,传递给Thread类对象。,,,,代 码,数 据,虚拟CPU,,Java线程模型,2019/9/30,Java多线程,10,一个普通的程序,顺序执行,class CommonTest1 {public static void main(String args[]){A a1 = new A(“ a1 “,1000);A a2 = new A(“ a2 “,1000);a1.tt();a2.tt();a2.setCount(2000); }} class A {private int count ;private String sflag;public A(){ }public A(String sflag,int count){this.sflag = sflag;this.count = count; }protected int getCount() {return count; }protected void setCount(int count) {this.count = count; }protected String getSflag() {return sflag; }protected void setSflag(String sflag) {this.sflag = sflag; }public void tt(){for (int i = 0;i count;i++){System.out.println(“ A in :“ + sflag + “ now is :“ + i);}}},2019/9/30,Java多线程,11,采用extends Thread方法创建线程,class ThreadTest1 {public static void main(String args[]) {At at1 = new At(“ at1 “, 1000); // 3 创建该线程对象At at2 = new At(“ at2 “, 1000);at2.setT1(at1);at1.start(); // 4 用Thread类的start()方法启动,等待处理// at1.start(); //再次调用,错误at2.start();/** for(int i = 0 ;i 2000;i++){ System.out.println(“CCCC : “ + i); }* at2.setCount(2000);*//** try { at2.join(); //at1.join(); } catch (InterruptedException e) { //* TODO Auto-generated catch block e.printStackTrace(); }*/System.out.println(“---------“);} }class At extends Thread { // 1 。 改写类的继承,继承自Threadprivate int count;private String sflag;Thread t1;public At() {}public At(String sflag, int count) {this.sflag = sflag;this.count = count;}protected int getCount() {return count;}protected void setCount(int count) {this.count = count;}protected String getSflag() {return sflag;}protected void setSflag(String sflag) {this.sflag = sflag;}public void tt() {for (int i = 0; i count; i++) {// this.currentThread();System.out.println(“ A in :“ + sflag + “ now is :“ + i);if (i == 333){At at3 = new At(sflag + “at3“,100);at3.start();}if (t1 != null) {if (i == 500) {try {t1.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}public void run() { // 2. 重写Thread类的run方法,在其中调用自己的业务逻辑tt(); // 对于业务逻辑中需要的参数一般以成员变量的方法来传入}protected Thread getT1() {return t1;}protected void setT1(Thread t1) {this.t1 = t1;}},2019/9/30,Java多线程,12,采用implements Runnable方法创建线程,class ThreadTest2 {public static void main(String args[]) {Ar ar1 = new Ar(“ar1“, 1000); // 定义并创建一个实现了Runnable接口的类对象Thread tar1 = new Thread(ar1);// 定义一个Thread对象,并用Runnable接口的实现类实例作为参数来创建该Thread对象Ar ar2 = new Ar(“ar2“, 1000);Thread tar2 = new Thread(ar2);tar1.start(); // 调用该Thread对象的start()方法启动线程// tar1.start(); // 再次调用,错误tar2.start();}} class Ar implements Runnable { // 1 。 改写类的实现接口Runnableprivate int count ;private String sflag;public Ar(){ }public Ar(String sflag,int count){this.sflag = sflag;this.count = count;}protected int getCount() {return count;}protected void setCount(int count) {this.count = count;}protected String getSflag() {return sflag;}protected void setSflag(String sflag) {this.sflag = sflag;}public void tt(){for (int i = 1;i NORM_PRIORITY“);}else if (Thread.currentThread().getPriority() == Thread.NORM_PRIORITY){Thread.currentThread().setPriority(Thread.MIN_PRIORITY);System.out.println(“ ----- NORM_PRIORITY --- MIN_PRIORITY“);}else if(Thread.currentThread().getPriority() == Thread.MIN_PRIORITY){Thread.currentThread().setPriority(Thread.MAX_PRIORITY);System.out.println(“ ----- MIN_PRIORITY --- MAX_PRIORITY“);/*try {//Thread.currentThread().sleep(1000 * 3);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}*/Thread.currentThread().yield();}else{}}System.out.println(“ A in :“ + sflag + “ now is :“ + i);} }public void run() { // 2. 实现Runnable的run方法,在其中调用自己的业务逻辑tt(); // 对于业务逻辑中需要的参数一般以成员变量的方法来传入} },2019/9/30,Java多线程,13,普通对象实现业务逻辑,继承对象实现Runnable,package com.umt.thdt1;class ThreadTest3 {public static void main(String args[]){Arr arr1 = new Arr(“arr1“,1000 * 100);Arr arr2 = new Arr(“arr2“,1000 * 100);Thread tarr1 = new Thread(arr1); Thread tarr2 = new Thread(arr2);//Thread tarr3 = new Thread(arr1); //一个线程对象放入到不同的线程体中,允许tarr2.setPriority(Thread.NORM_PRIORITY);tarr1.setPriority(Thread.MIN_PRIORITY);tarr1.start();tarr2.start();/*for (int i = 1 ; i 2000;i ++){tarr2.setPriority(Thread.MAX_PRIORITY);}*///tarr3.start();} }class Arr extends A implements Runnable{public Arr(){super();}public Arr(String sflag,int count){super(sflag,count);/*this.setCount(count);this.setSflag(sflag);*/ }public void run() {System.out.println(Thread.currentThread());tt(); // } },2019/9/30,Java多线程,14,创建线程,通过java.lang.Thread来创建一个线程 Thread的构造器: Thread() Thread(Runnable target) Thread(Runnable target, String name) Thread(String name) Thread(ThreadGroup group, Runnable target) Thread(ThreadGroup group, Runnable target, String name) Thread(ThreadGroup group, String name),2019/9/30,Java多线程,15,启动线程,每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。 使用start()方法,线程进入Runnable(可运行)状态,它将向线程调度器注册这个线程。 调用start()方法并不一定马上会执行这个线程,正如上面所说,它只是进入Runnable 而不是Running。 注意,不要直接在程序中调用线程的run()方法。,2019/9/30,Java多线程,16,创建并启动线程例子(例:TestThread),public class TestThread extends Thread{public void run(){for(int i = 0;i100;i++)System.out.println(“Count:“+i);} public static void main(String[] args){TestThread tt = new TestThread();//注意,不要直接调用run方法tt.start();} },2019/9/30,Java多线程,17,使用Runnable接口,由于继承了Thread后,类再不能继承别的类,所以一般我们采用实现Runnable接口的方法来创建线程。 提供一个实现接口Runnable的类,实现run()方法。 得到这个类的实例A。 New 这个一个Thread对象,同时A作为参数传入。例如:Thread runner=new Thread(A); 调用start启动线程例如:runner.start();,2019/9/30,Java多线程,18,用Runnable创建线程(例: RunnableThread ),public class RunnableThread implements Runnable{//实现接口Runnable中的run方法public void run(){for (int k = 0;k10;k++){System.out.println(“Count:“+k);} } … … },2019/9/30,Java多线程,19,Runnable接口,使用Runnable接口 可以将CPU,代码和数据分开,形成清晰的模型; 还可以从其他类继承; 保持程序风格的一致性。 直接继承Thread类 不能再从其他类继承; 编写简单,可以直接操纵线程,无需使用Thread.currentThread()。,2019/9/30,Java多线程,20,多线程示例,例MultitThread1 例MultitThread2设定了不同的优先级 例MultitThread3设定sleep()或yield() t1.setPriority(Thread.MIN_PRIORITY); t2.setPriority(Thread.NORM_PRIORITY); for (int k = 0; k 100; k++) {Thread t = Thread.currentThread();//获得当前线程实例System.out.println(t.getName());//打印线程名(系统分配) },2019/9/30,Java多线程,21,线程的优先级,线程的优先级用数字来表示,范围从1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORITY。一个线程的缺省优先级是5,即Thread.NORM_PRIORITY。下述方法可以对优先级进行操作: int getPriority(); //得到线程的优先级 void setPriority(int newPriority); //当线程被创建后,可通过此方法改变线程的优先级 注意:并不是所有的操作系统都支持所有级别。永远不要依赖优先级来决定你的线程运行顺序。,2019/9/30,Java多线程,22,线程让步和睡眠,对于程序员来说,在编程时要注意给每个线程执行的时间和机会,主要是通过让步(yield()方法)或者让线程睡眠的办法(调用sleep()方法)来让当前线程暂停行一段时间,然后由其它线程来争夺执行的机会。,2019/9/30,Java多线程,23,线程的join方法(例:TestJoin),Thread API 包含了等待另一个线程完成的方法:join() 方法。当调用 join() 时,调用线程将阻塞,直到目标线程完成为止。 join() 通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。,2019/9/30,Java多线程,24,线程的join方法(例:TestJoin),JoinThread r = new JoinThread();Thread t = new Thread(r);t.start();try{t.join();}catch(InterruptedException e){},2019/9/30,Java多线程,25,多线程的互斥与同步,前面所提到的线程都是独立的,而且异步执行,也就是说每个线程都包含了运行时所需要的数据或方法,而不需要外部的资源或方法,也不必关心其它线程的状态或行为。但是经常有一些同时运行的线程需要共享数据,此时就需考虑其他线程的状态和行为,否则就不能保证程序的运行结果的正确性。,2019/9/30,Java多线程,26,多线程的互斥与同步,有一个Counter类,有一个成员变量lngCounter; 一个线程对lngCounter进行++运算,循环100次,另一个线程对lngCounter进行--运算,也循环100次,最后的结果是多少?public void add() {long v;System.out.println(“before add:“ + (v = counter.getLngCounter()));v++;counter.setLngCounter(v);System.out.println(“after add=“ + v);},2019/9/30,Java多线程,27,多线程的互斥与同步,两个线程并非顺序交替执行; 两个线程获得的counter值出现不一致。其中有一个是旧的。 必须让一个线程的add()或del()都执行完,才能让另一个线程执行。 有何方法?,2019/9/30,Java多线程,28,互斥锁,为解决操作的不完整性问题,在Java 语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为“ 互斥锁“ 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。 关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问。,2019/9/30,Java多线程,29,互斥锁synchronized,synchronized (counter){ int i = counter.getCount(); System.out.println(sname + j + “ before “ + i); //System.out.println(“now in :“ + sname + “ count = “ + i); AddCounter(i - 1); System.out.println(sname + j + “ after “ + counter.getCount()); },2019/9/30,Java多线程,30,完整例子,class ThreadTest4 {public static void main(String argc[]) {Counter ct = new Counter();C2 c2 = new C2(ct, “ c2 “);C1 c1 = new C1(ct, “ c1 “);c2.start();c1.start();try {c2.join();c1.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(ct.getCount());}}class Counter {private int count = 1000;protected int getCount() {return count;}protected void setCount(int count) {this.count = count;} }class C1 extends Thread {private Counter counter;private String sname;public C1(Counter cc, String s1) {this.counter = cc;this.sname = s1;}public Counter getCounter() {return counter;}public void setCounter(Counter counter) {this.counter = counter;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public void run() {for (int j = 0; j 100; j++) {synchronized (counter){int i = counter.getCount();System.out.println(sname + j + “ before “ + i);//System.out.println(“now in :“ + sname + “ count = “ + i);AddCounter(i - 1);System.out.println(sname + j + “ after “ + counter.getCount());}}}public void AddCounter(int i) {counter.setCount(i);} }class C2 extends Thread {private Counter counter;private String sname;public C2(Counter cc, String s1) {this.counter = cc;this.sname = s1;}public Counter getCounter() {return counter;}public void setCounter(Counter counter) {this.counter = counter;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public void run() {for (int j = 0; j 100; j++) {synchronized (counter){int i = counter.getCount();System.out.println(sname + j + “ before “ + i);//System.out.println(“now in :“ + sname + “ count = “ + i);AddCounter(i + 1);System.out.println(sname + j + “ after “ + counter.getCount());}}}public void AddCounter(int i) {counter.setCount(i);}},2019/9/30,Java多线程,31,互斥锁synchronized,synchronized 除了象上面讲的放在对象前面限制一段代码的执行外,还可以放在方法声明中,表示整个方法为同步方法,则将this对象作为锁。 public synchronized void push(char c){ … },2019/9/30,Java多线程,32,互斥锁synchronized,如果一个线程一直占用一个对象的锁,则其他的线程将永远无法访问该对象,因此,需要在适当的时候,将对象锁归还。 当线程执行到synchronized()块结束时,释放对象锁。 当在synchronized()块中遇到break, return或抛出exception,则自动释放对象锁。 当一个线程调用wait()方法时,它放弃拥有的对象锁并进入blocked 状态。,2019/9/30,Java多线程,33,前面CounterSyn的例子,要求lngCounter的值只能在0-20之间变化。 在两个线程的add()或del()方法中首先检查lngCounter的值,如果lngCounter的值达到临界值,则通过wait()放弃释放Coun ter对象锁并使线程挂起,直到得到Counter对象的notify()通知或者时间到期才恢复运行,线程协作,2019/9/30,Java多线程,34,while(counter.getLngCounter()==7){ try { counter.wait(); } catch (InterruptedException e) {} } long v = counter.getLngCounter(); v++; counter.setLngCounter(v); counter.notify();,线程协作,2019/9/30,Java多线程,35,wait()方法,wait()方法是Object对象的方法,而不是Thread的方法。 wait()方法只可能在synchronized块中被调用。 wait()被调用时,原来的锁对象打开锁,线程进入blocked状态。 wait()时间到期或被notify()唤醒的线程从wait()后面的代码开始继续执行。 思考:wait()方法与sleep()的异同!试试用sleep()代替wait(),2019/9/30,Java多线程,36,notify()和notifyAll(),只能在synchronized中被调用。 notify它会唤起同一个锁对象上的一个等待线程.但如果有几个线程在等待列表中,它无法决定是哪一个线程被唤醒。所以,为了防止不该唤醒的线程被唤醒,应该调用notifyAll,让所有的等待线程都有机会运行。,2019/9/30,Java多线程,37,例子,package com.umt.thdt2;class ThreadTest4 {public static void main(String argc[]) {Counter ct = new Counter();C2 c2 = new C2(ct, “ c2 “);C1 c1 = new C1(ct, “ c1 “);C2 c3 = new C2(ct, “ c2 “);C1 c4 = new C1(ct, “ c1 “);c3.start();c4.start();c2.start();c1.start();try {c2.join();c1.join();c3.join();c4.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(ct.getCount());}}class Counter {private int count = 1000;public int getCount() {return count;}public void setCount(int count) {this.count = count;}public synchronized void addCounter(int j,String sname) {while (this.getCount() 1007){try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}int i = this.getCount();System.out.println(sname + j + “ before “ + i);//System.out.println(“now in :“ + sname + “ count = “ + i);this.setCount(i+1);this.notifyAll();System.out.println(sname + j + “ after “ + this.getCount());} public synchronized void delCounter(int j,String sname) {while (this.getCount() 990){try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}int i = this.getCount();System.out.println(sname + j + “ before “ + i);//System.out.println(“now in :“ + sname + “ count = “ + i);this.setCount(i - 1);this.notifyAll();System.out.println(sname + j + “ after “ + this.getCount());} }class C1 extends Thread {private Counter counter;private String sname;public C1(Counter cc, String s1) {this.counter = cc;this.sname = s1;}public Counter getCounter() {return counter;}public void setCounter(Counter counter) {this.counter = counter;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public void run() {for (int j = 0; j 100; j++) {/*synchronized (counter){delCounter(j);}*/counter.delCounter(j,sname);}} }class C2 extends Thread {private Counter counter;private String sname;public C2(Counter cc, String s1) {this.counter = cc;this.sname = s1;}public Counter getCounter() {return counter;}public void setCounter(Counter counter) {this.counter = counter;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public void run() {for (int j = 0; j 100; j++) {/*synchronized (counter) {addCounter(j);}*/if (j % 19 == 0) {try {sleep(0,100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}counter.addCounter(j,sname);}}},2019/9/30,Java多线程,38,线程控制,2019/9/30,Java多线程,39,线程状态,2019/9/30,Java多线程,40,线程状态,Runnable,Running,Blocked,,New,start(),run() 运行完毕,线程调度,阻塞事件,解除阻塞,Dead,2019/9/30,Java多线程,41,中断线程,1.interrupt()将一个标志interrupted设为true,并不直接中断线程的运行。要想中断线程,必须由线程(isInterrupted() )检查该标志,然后退出run() 方法。 2.对于睡眠(sleep())或等待(wait())状态的线,调用interrupt(),在interruptedException中捕获并处理。 3.对于非睡眠或等待状态的线程,调用interrupt()并不能立即产生InterruptedException事件。,2019/9/30,Java多线程,42,死锁,死锁 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁 如:哲学家问题(thinking or eating) 解决方法 专门的算法、原则 尽量减少同步资源的定义,2019/9/30,Java多线程,43,线程中断实例,class ThreadInterrupt extends Thread {private int j;private String sname;public ThreadInterrupt(String sname){this.sname = sname;}public void run() {int i = 0;boolean flag = true;while (!this.isInterrupted() ) {try {sleep((long)Math.random() * 100); //随机睡眠j = i++ ;System.out.println(sname + j);if (i % 300 == 0) {InterruptedException e = new InterruptedException(“ 300 out “);this.interrupt();throw e;}} catch (InterruptedException e) {e.printStackTrace();} finally {}System.out.println(sname + “ run over “);}}public static void main(String args[]){ThreadInterrupt ti = new ThreadInterrupt(“t1--:“);ti.start();}public int getJ() {return j;}},
展开阅读全文
  微传网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
0条评论

还可以输入200字符

暂无评论,赶快抢占沙发吧。

关于本文
本文标题:第15讲 Java多线程.ppt
链接地址:https://www.weizhuannet.com/p-10035952.html
微传网是一个办公文档、学习资料下载的在线文档分享平台!

网站资源均来自网络,如有侵权,请联系客服删除!

 网站客服QQ:80879498  会员QQ群:727456886

copyright@ 2018-2028 微传网络工作室版权所有

     经营许可证编号:冀ICP备18006529号-1 ,公安局备案号:13028102000124

收起
展开