《java教程第10章线程》由会员分享,可在线阅读,更多相关《java教程第10章线程(23页珍藏版)》请在金锄头文库上搜索。
1、第第10章章 线程线程线程与进程的基本概念了解线程在其生命周期中状态的转换会用两种方法熟练创建线程;能熟练运用同步10.1 线程和进程线程和进程现代操作系统都支持多任务,主要有两种形式:基于线程和基于进程;从本质上说,进程就是独立运行的程序,有独立的指令序列,独立的数据空间和资源;线程则是依附于进程存在的独立的指令序列,一个进程中可以有多个线程。这些线程共享进程的数据和资源,线程有独立的生命周期;因为没有存储空间的交换,线程间的切换优于进程,因此尽量用多线程。Java中线程分为:用户线程和守护线程,特点如下:用户线程可以转换为守护线程,转换时机只有在新建态和终止态进行;守护线程运行于系统后台,
2、一般是为用户线程服务,用户线程运行于系统前台,当所有的用户线程都终止时,JVM会杀死守护线程。单线程实例单线程实例class SingleThread private String id;public SingleThread (String str)id = str;public void run() for(int i=0; i4; i+)for(int j=0; j100000000; j+); System.out.println(id+ is running.); class Test public static void main(String args)SingleThread
3、dog = new SingleThread (doggy); SingleThread cat = new SingleThread (kitty); (); ();10.2 线程的状态及其生命周期线程的状态及其生命周期就绪运行死亡阻塞休眠等待start()notify()I/O结束yield()I/O请求stop()run结束wait()sleep()notifyAll()分派新建新建态:用new语句创建一个Thread对象时。该状态的线程不会立即被执行,但会分配系统资源;就绪态:当线程调用start方法后,CPU会为其分配相应的时间,这时线程就绪了;运行态:当线程内的代码块开始执行时,该
4、线程便开始运行。一旦线程开始运行,它不必始终保持运行状态,因此很多书中把就绪态和运行态统称为可运行状态;阻塞/挂起态:有人调用该线程的sleep()方法;该线程调用了wait方法;该线程试图锁定一个当前被另一个线程锁定了的对象;有人调用了该线程的suspend方法;终止状态:由于run方法的正常退出而自然死亡;没有抓取到的异常事件终止了run方法的执行,从而导致线程突然死亡;有人调用了该线程的stop方法。10.2.1 线程的状态说明线程的状态说明10.3 线程的优先级线程的优先级对新建的线程通常继承其父类的优先级。用户可以通过setPriority方法来修改系统自动设定的线程优先级。线程优先
5、级的使用原则是与系统有着密切关系的,当JVM取决于主机平台的线程机制时,线程的调度完全受线程机制的支配。10.4 线程的创建线程的创建Thread类:它是线程类的超类,它是一个线程有生命周期,继承它的类本身也是一个线程;Runnable接口:它只定义了线程的行为,由实现其run方法来实现,但它没有线程的生命周期,实现它的类本身不是一个线程;启动线程时,都应调用线程的start方法。10.4.1 继承继承Thread类类覆盖其run方法,其余方法继承Thread的class MultThread extends Thread private String id; public MultThrea
6、d (String str) id = str;public void run() for(int i=0; i4; i+)for(int j=0; j100000000; j+); System.out.println(id+ is running.); class Test public static void main(String args) MultThread dog = new MultThread (doggy); MultThread cat = new MultThread (kitty); (); (); 注意在上页的程序代码中,不能直接调用run方法,这样只是把run方
7、法运行一遍而已,并没有激活线程。正确的方式是调用由Thread类继承而来的start方法,然后由这个方法在计划表(scheduler)中登录这个线程,最后这个线程开始运行时,run方法自然会被调用。不管是继承Thread创建线程,还是实现Runnable接口创建线程,都应该调用start方法启动线程;由结果可以看出,这两个线程是一起运行的。但哪一个字符串先出现则不一定,看谁抢到CPU的资源。10.4.2 启动线程的注意事项启动线程的注意事项10.4.3 实现实现Runnable接口接口class RunnableThread implements Runnable private String
8、 id; public RunnableThread (String str) id = str; public void run() for(int i=0; i4; i+) for(int j=0; j100000000; j+); System.out.println(id+ is running.); class Test public static void main(String args) RunnableThread dog = new RunnableThread (doggy); RunnableThread cat = new RunnableThread (kitty)
9、; Thread t1 = new Thread(dog); Thread t2 = new Thread(cat); t1.start(); t2.start(); 当一个类已经继承了另一个类时,可通过实现Runnable接口创建线程;用实现Runnable接口创建线程时,可以使多个线程共享同一资源;用实现Runnable接口创建线程时,因为本类没有线程的生命周期,因此必须新建一个线程。10.4.4 实现实现Runnable接口注意事项接口注意事项10.5 Thread类常用方法类常用方法sleep方法:是当前运行的线程休眠一定时间后运行。class MultThread extends T
10、hread private String id; public MultThread (String str) id = str; public void run()for(int i=0; i4; i+)try sleep(1000); catch(InterruptedException e) (); System.out.println(id+ is running.); yield方法:暂停当前正在执行的线程对象,并执行其他线程class MultiThreadpublic static void main(String args) MyThread mt = new MyThread
11、();();int index = 0;while(true) if(index+ = 1000) break;System.out.println(main );class MyThread extends Thread public void run() while(true) System.out.println(MyThread);yield();join方法当前线程等待调用线程运行结束后再运行public static void main(String args) MultThread dog = new MultThread (doggy); MultThread cat = ne
12、w MultThread (kitty); (); try(); catch(InterruptedException (); (); try(); catch(InterruptedException (); System.out.println(main() method finished); Suspend方法和resume方法是调用线程挂起和唤醒public class Tortoise implements Runnableprivate Thread r; public TortoiseB( Thread r) = r;public void run( )for( int i=0;
13、 i=1000; i+=10 )( 乌龟- + (i) );try( 100 );catch( Exception e )if( i = 1000 )try( Tortoise is Winner! );( Rubbit awake! );();catch( Exception e )public class Rubbit implements Runnablepublic void run()for( int i=0; i0) try Thread.sleep(10);catch (InterruptedException e) ();System.out.println(Thread.cu
14、rrentThread().getName() + sell tickets + tickets);tickets - -;class TicketsSystem public static void main(String args) SellThread st = new SellThread();Thread t1 = new Thread(st);Thread t2 = new Thread(st);Thread t3 = new Thread(st);Thread t4 = new Thread(st);t1. start(); t2. start(); t3. start(); t
15、4. start();没有同步时的情况没有同步时的情况10.6.2 同步方法同步方法方法声明时加上synchronized关键字,此时锁的是类的当前对象:thisclass SellThread implements Runnable int tickets = 100;public void run() while(true) sell();public synchronized void sell() if(tickets0) tryThread.sleep(10);catch (InterruptedException e) ();System.out.println(Thread.cu
16、rrentThread().getName() + sell tickets + tickets);tickets-;同步块,锁某一对象,语法:synchronized(对象)实现语句class SellThread implements Runnable Object obj = new Object();int tickets = 100;public void run() while(true) synchronized (obj) if(tickets0) try Thread.sleep(10); catch (InterruptedException e) ();System.ou
17、t.println(Thread.currentThread().getName() + sell tickets + tickets);tickets-;10.6.3 同步块同步块10.6.4 wait()和()和notify()()wait()方法和notify()方法都是Object类中的方法,用对象来调用;当调用某对象的wait()方法时,当前线程进入该对象的等待队列中;当调用某对象的notify()方法时,唤醒该对象等待队列中的某个线程(多个等待线程时,随机唤醒一个);这两个方法的调用通常放在同步方法或同步块中;将线程放到谁的等待队列中则代码必须持有谁的锁;在谁的等待队列中唤醒线程,则必须持有谁的锁。现在有一仓库,库存产品不能出现积压,也不应该出现提前销售或者消费的情况,即当库存产品为1时,应该销售,而不能继续生产;反之,当库存产品数量为0是就应该生产而不能继续销售,这个案例就需要线程同步来实现,在本例中需要两个线程一是生产者线程,二是消费者线程,在这两个线程中公用一个仓储对象,仓储对象中提供生产和销售的方法,分别被两个线程调用,共同操作仓储对象中的产品数量。10.6.5 线程同步实现仓储问题线程同步实现仓储问题