1、Java 多线程,教学目标,正确理解多线程概念。 能够区分线程与进程的区别。 掌握Java中创建线程的两种方式。 理解线程优先级和死锁的概念。 掌握线程的同步和通信。,教学任务,在Java中创建线程,使用线程的同步和通信实现邮件收发,相关实践知识1,打开NetBeas,相关实践知识2,在NetBeans中新建名为MailBox的项目,利用多线程知识实现邮件收发功能 多线程的相关概念 创建com.handson 包,相关实践知识3,新建类MailBox,用来存储邮件对象,package mailbox; public class MailBox private boolean newMail;
2、/是否有新的邮件private String text; /邮件内容public boolean isNewMail() /判断是否有新的邮件public String getText() /取走邮件 public void setText(String text) /放置邮件 ,相关实践知识4,新建类Sender(创建线程),public class Sender implements Runnable public void run() synchronized(mailBox)while(mailBox.isNewMail()mailBox.wait();Thread.sleep(100
3、0); mailBox.notify();,相关实践知识5,新建类Receiver(创建线程)用来从邮箱取出邮件,public class Receiver extends Thread public void run() synchronized(mailBox) ,相关实践知识6,新建类Test测试类(主线程),public class Test MailBox mailbox = new MailBox(); Sender sender = new Sender(mailbox); Thread sendThread = new Thread(sender); Receiver rece
4、iveThread = new Receiver(mailbox); sendThread.setPriority(Thread.MIN_PRIORITY); sendThread.start(); receiveThread.interrupt(); public static void main(String args) ,相关实践知识6,其它相关知识点 死锁 线程组 守护线程,相关实践知识7,运行,总结,Java 以类和接口的形式为多线程提供内置支持。 Java 程序启动时,一个线程立刻运行,该线程称为主线程。 两种方式可以创建线程:继承Thread类、实现Runnable 接口。 守护
5、线程是作为后台线程并为其他线程提供服务的线程。 同步是用于确保资源一次只能被一个线程使用的过程。 wait-notify机制用来处理线程间通信。,相关概念,多任务操作系统 周期性地将CPU时间划分给每个进程,使操作系统得以同时执行一个以上的进程 进程 线程 一个程序或进程能够包含多个线程,这些线程可以根据程序的代码执行相应的指令。在多处理机计算机上实现多线程时,线程可以并行工作,提高程序执行效率。Java语言的一大特性就是提供了优秀的多线程控制环境。,创建线程,Java语言中使用Thread类及其子类的对象表示线程。 Java语言中通过两种途径创建线程: 一种是用Thread类或其子类创建线程
6、。 另外是实现Runnable接口。,主线程,每个Java程序都有一个默认的主线程。 程序开始时它就执行。它是产生其他子线程的线程,而且它必须最后执行,它执行各种关闭动作。 尽管主线程在程序启动时创建,但它可以由一个Thread对象控制。它通过currentThread()获得它的一个引用。 对于应用程序applcation来说main方法就是一个主线程。,Thread类,Thread 类是一个具体的类,即不是抽象类,该类封装了线程的行为。所有以这个类派生的子类或间接子类,均为线程。 可以通过创建的Thread类的子类中重写run(),加入线程所要执行的代码来创建线程。,Thread类的构造方
7、法,public Thread() public Thread(Runnable target) public Thread(ThreadGroup group, Runnable target, String name) public Thread(Runnable target, String name) public Thread(String name) public Thread(ThreadGroup group, Runnable target) public Thread(ThreadGroup group, Runnable target, String name, long
8、 stackSize) public Thread(ThreadGroup group, String name),Thread类的重要方法,static int activeCount() static Thread currentThread() static int enumerate(Thread tarray) void join() void run() void setDaemon(boolean on) void setName(String name) String getName() void setPriority(int newPriority) static void
9、 sleep(long millis) void start() void yield() boolean isDaemon() void setDaemon(boolean on) boolean isAlive(),Runnable接口,Runnable接口只包含了一个抽象方法run()。我们自己定义的类实现Runnable接口并提供这一方法,并将将线程代码写入其中。 Runnable接口并没有任何对线程的支持,我们还必须创建Thread类的实例,通过Thread类的构造函数public Thread(Runnable target)来实现。,守护线程,守护线程是在后台运行并且为其他线程提
10、供服务的线程。 任何一个Java线程都能成为守护线程。它是作为运行于同一个进程内的对象和线程的服务提供者。 当正在运行的线程都是守护线程时,Java虚拟机就会退出。 使用守护线程做一些不是很严格的工作,防止线程随时结束时产生的不良的后果。 Thread类的setDaemon(Boolean on)方法将该线程标记为守护线程或用户线程。isDaemon()方法测试该线程是否为守护线程。,线程组,使得多个线程集于一个对象内,能对它们实行整体操作。 Java线程组由ThreadGroup类实现。 当线程产生时,可以指定线程组或由实时系统将其放入某个缺省的线程组内。 线程只能属于一个线程组,并且当线程
11、产生后不能改变它所属的线程组。,线程状态,创建一个新的线程的生命周期如下状态: 新建状态(New Thread) 就绪状态(Ready) 运行状态(Running) 阻塞状态(Blocking) suspend() sleep() wait() 死亡态(Dead),线程调度和优先级,以某种顺序在单CPU情况下执行多线程被称为调度(scheduling)。 Java采用的是一种简单、固定的调度法,即固定优先级调度。这种算法是根据处于可运行态线程的相对优先级来进行调度。 当线程产生时,它继承原线程的优先级。 线程的优先级是通过Thread类中定义常量实现的。 它有三个常量: MIN_PRIORIT
12、Y NORM_PRIORITY MAX_PRIORITY 可以使用setPriority(int newPriority) 方法更改线程的优先级,newPriority的值必须为1到10的范围。我们还可以使用getPriority()方法返回线程的优先级。,线程同步,在Java中采用线程的同步机制。线程的同步用于线程共享数据,转换和控制线程的执行,保证内存的一致性。 在Java中,运行环境使用锁(Monitor)来解决线程同步的问题。 当调用同步(synchronized)方法时,该线程就获得了锁。该方法的边界上实行严格的互斥,在同一时刻,只允许一个线程进入该方法,其它希望进入该方法的线程必须
13、等待。,同步化实现,调用被synchronized关键字修饰的方法 。 定义一个synchronized同步块。,死锁,死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。 死锁形成条件包括: 互斥条件,即资源是不能够被共享的。 至少有一个进程在使用一个资源却在等待另外一个线程所持有的一个资源。 资源不能够被进程抢占。 必须有循环的等待。,wait-notify的机制,Java中提供了一种wait-notify的机制,进行进程间的通信。它主要包括: wait() notify() notifyAll (),