第9章Java的多线程机制.PPT
第9章 Java的多线程机制,本章主要讲述了线程的概念,线程的创建,线程的管理。,例9.1用类Thread的子类创建线程class CalculateThread extends Thread private String name;public CalculateThread(String name)super(name);this.name=name;,public void run()System.out.println(name+线程说:先睡1s(秒),再计算圆周率的平方根);try Thread.sleep(1000);catch(InterruptedException ie)System.out.println(圆周率的平方根为:+Math.sqrt(Math.PI);System.out.println(name+线程说:再见!);,class PrintThread extends Thread private String name;public PrintThread(String name)super(name);this.name=name;,public void run()System.out.println(name+线程说:我马上打印10颗星!);for(int i=1;i=10;i+)System.out.print(*);System.out.println();System.out.println(name+线程说:再见!);,class ThreadTestpublic static void main(String args)CalculateThread t1=new CalculateThread(计算);PrintThread t2=new PrintThread(打印);System.out.println(启动计算线程t1);t1.start();System.out.println(启动打印线程t2);t2.start();System.out.println(main方法说:再见!);,该程序产生的输出是:启动计算线程t1启动打印线程t2main方法说:再见!计算线程说:先睡1s(秒),再计算圆周率的平方根打印线程说:我马上打印10颗星!*打印线程说:再见!圆周率的平方根为:1.7724538509055159计算线程说:再见!,Java语言支持多线程,在一个java程序中可以同时执行多个线程,使得使用java程序的用户可以减少等待时间提高工作效率。线程是一个执行体,该执行体的指令流只有一个起点、一个终点,执行中的某时刻只有一个执行点。线程不能单独存在,只能是程序中的一个部分。在一个程序中可以使用多个线程,这些线程可以同时运行,每个线程完成不同的任务。,线程之间可以共享计算机系统分配给这个程序的资源(为程序分配的内存和外部设备的使用权等)。线程之间可利用共享的内存空间进行信息交换(线程间通信)。在Java中线程是主动对象。主动对象不但能接收消息也能向其他对象发送消息。声明一个Thread的子类。在子类中重构方法run,再声明子类的构造方法。然后,创建该子类的对象。public viod start()throws IllegalThreadStateException启动当前线程,方法立即返回。若该线程启动过了,再次调用方法start则抛出IllegalThreadStateException异常。线程启动后若获得CPU使用权则调用本线程的run方法。,例9.2 通过实现接口Runnable创建线程class CalculateClass implements Runnable private String name;public CalculateClass(String name)this.name=name;,public void run()System.out.println(name+线程说:先睡1s(秒),再计算圆周率的平方根);try Thread.sleep(1000);catch(InterruptedException ie)System.out.println(圆周率的平方根为:+Math.sqrt(Math.PI);System.out.println(name+线程说:再见!);,class PrintClass implements Runnable private String name;public PrintClass(String name)this.name=name;,public void run()System.out.println(name+线程说:我马上打印10颗星!);for(int i=1;i=10;i+)System.out.print(*);System.out.println();System.out.println(name+线程说:再见!);,class RunnableTestpublic static void main(String args)CalculateClass calculateObj=new CalculateClass(计算);PrintClass printObj=new PrintClass(打印);Thread t1=new Thread(calculateObj);Thread t2=new Thread(printObj);System.out.println(启动计算线程t1);t1.start();System.out.println(启动打印线程t2);t2.start();,System.out.println(main方法说:再见!);,先声明一个实现接口Runnable的类,利用该类创建主动对象,在用这个主动对象作为构造方法的参数来创建线程对象。public static void sleep(long millis)throws InterruptedException使当前线程放弃执行(睡眠)millis毫秒。若当前线程在睡眠过程中由其他线程中断则睡眠过程结束并抛出InterruptedException异常。public Thread(Runnable runObj)创建一新线程。该线程使用主动对象runObj的run方法。新线程的名字由系统产生。,例9.2线程状态的控制class CalculateThread extends Thread private String name;public CalculateThread(String name)super(name);this.name=name;,public void run()System.out.println(name+线程说:先睡1s(秒),再计算圆周率的平方根);try Thread.sleep(1000);catch(InterruptedException ie)System.out.println(圆周率的平方根为:+Math.sqrt(Math.PI);System.out.println(name+线程说:再见!);,class PrintThread extends Thread private String name;public PrintThread(String name)super(name);this.name=name;,class RunnableTestpublic static void main(String args)CalculateClass calculateObj=new CalculateClass(计算);PrintClass printObj=new PrintClass(打印);Thread t1=new Thread(calculateObj);Thread t2=new Thread(printObj);System.out.println(启动计算线程t1);t1.start();System.out.println(启动打印线程t2);t2.start();,System.out.println(main方法说:再见!);,先声明一个实现接口Runnable的类,利用该类创建主动对象,在用这个主动对象作为构造方法的参数来创建线程对象。public static void sleep(long millis)throws InterruptedException使当前线程放弃执行(睡眠)millis毫秒。若当前线程在睡眠过程中由其他线程中断则睡眠过程结束并抛出InterruptedException异常。public Thread(Runnable runObj)创建一新线程。该线程使用主动对象runObj的run方法。新线程的名字由系统产生。,例9.3 线程状态的控制class CalculateThread extends Thread private String name;public CalculateThread(String name)super(name);this.name=name;,public void run()System.out.println(name+线程说:先睡1s(秒),再计算圆周率的平方根);try Thread.sleep(1000);catch(InterruptedException ie)System.out.println(圆周率的平方根为:+Math.sqrt(Math.PI);System.out.println(name+线程说:再见!);,class PrintThread extends Thread private String name;public PrintThread(String name)super(name);this.name=name;,public void run()System.out.println(name+线程说:我马上打印10颗星!);for(int i=1;i=10;i+)System.out.print(*);System.out.println();try suspend();catch(SecurityException se)System.out.println(name+线程说:再见!);,class ThreadStatepublic static void main(String args)CalculateThread t1=new CalculateThread(计算);PrintThread t2=new PrintThread(打印);System.out.println(启动计算线程t1);t1.start();System.out.println(启动打印线程t2);t2.start();,tryt1.join();catch(InterruptedException Ie)tryt2.resume();catch(SecurityException se)tryt2.join();catch(InterruptedException ie)if(!t1.isAlive()System.out.println(计算线程结束了);if(!t2.isAlive()System.out.println(打印线程结束了);System.out.println(main方法说:再见!);,本程序产生的输出是:启动计算线程启动打印线程计算线成说:先睡4s(秒),再计算圆周率的平方根打印线成说:我马上打印10颗星!*圆周率的平方根为:1.772 453 850 905 515 9计算线程说:再见!打印线程说:再见!计算线程结束了打印线程结束了main方法说:再见!,我们可用isAlive来判断某线程是否启动过而又未进入结束状态。语句t1.join();等待计算线程结束语句t2.resume();恢复打印线程语句suspend();将当前线程挂起,进入阻塞状态。其它线程调用当前线程的方法resume()后,将当前线程唤醒,进入就绪状态。处于阻塞状态的线程可用方法stop()结束。,例9.4 优先级相同的线程class SamePrioritypublic static void main(String args)new DemoA(长江).start();new DemoA(黄河).start();,class DemoA extends Thread private String name;public DemoA(String s)super(s);this.name=s;,public void run()for(int i=0;i=4;i+)System.out.print(+currentThread().getName();yield();System.out.println();,该程序的输出是:长江 黄河 东海 东海 东海 东海 东海 长江 黄河 长江 黄河 长江 黄河 长江Java线程的优先级是一个在1到10之间的整数。未设定优先级的线程其优先级为缺省值5。在类Thread中分别用类常量 MIN_PRIORITY、NORM_PRIORITY和MAX_PROIORITY表示1、5、10这3个数。在程序中可利用方法setPriority(int newPriority)将当前线程的优先级指定为newPriority的值。,一个线程可以创建另一个线程,被创建的线程的优先级与创建者的相同。Java的调度发式抢占式的,即Java保证优先级最高的线程线运行。当一个线程运行结束或处于阻塞状态后,Java总是从就绪队列中挑选优先级最高的线程进入运行状态。,例9.5 运行优先级不同的线程class TwoPrioritypublic static void main(String args)new DemoA(长江).start();new DemoA(黄河).start();DemoA da=new DemoA(东海);da.setPriority(Thread.MAX_PRIORITY);da.start();,class DemoA extends Thread private String name;public DemoA(String s)super(s);this.name=s;,public void run()for(int i=0;i=4;i+)System.out.print(+currentThread().getName();yield();System.out.println();,该程序的输出是:长江 黄河 东海 东海 东海 东海 东海 长江 黄河 长江 黄河 长江 黄河 长江本程序各次运行的结果可能不一样,但优先级高的“东海”线程会较早地执行完。多线程程序不保证输出的再现性。语句setPriority(Thread.MAX_PRIORITY);将当前线程的优先级指定为最大值。,例9.7 线程同步运行class ShareIntAbleprivate int value;private boolean setAble=true;public synchronized void set(int val)while(!setAble)trywait();catch(InterruptedException ie),setAble=false;value=val;notify();public synchronized int get()while(setAble)trywait();catch(InterruptedException ie)setAble=true;,notify();return value;class ProduceIntB extends Threadprivate ShareIntAble si;public ProduceIntB(ShareIntAble siForm)si=siForm;public void run()for(int i=1;i=4;i+)si.set(i);,System.out.println(产生的新数据是:+i);class ConsumeIntB extends Thread private ShareIntAble si;public ConsumeIntB(ShareIntAble siForm)si=siForm;public void run()for(int i=1;i=4;i+)int value=si.get();,System.out.println(读到的数据是:+value);public class SynchronizeTestB public static void main(String args)ShareIntAble si=new ShareIntAble();ProduceIntB p=new ProduceIntB(si);ConsumeIntB c=new ConsumeIntB(si);p.start();c.start();,本程序某次运行的结果是:产生的新数据是:读到的数据是:读到的数据是:产生的新数据是:产生的新数据是:读到的数据是:读到的数据是:产生的新数据是:,变量setAble,其值为ture 表示生长线程可以产生新数据,否则不能。在访问value的方法set和get声明的头部增加了修饰词synchronized。这就使ShareIntAble的每个对象都会有1把锁。在方法set和get中,在访问value之前要借助变量setAble判断是否允许访问,若不允许则调用方法wait使当前线程等待,之后,若当前线程被生产线程唤醒则继续执行wait()语句后的对seyAble重新赋值等3个语句。在方法set和get退出前都要调用方法notify使当前线程交出锁并唤醒等待锁的线程。多个线程共享数据时可能出现死锁现象。Java在语言一级上解决了给对象配锁、获得锁、等待和交出锁等操作。,