Designed by Chiyong,?20051
Java2 网络编程基础多线程第十章
Designed by Chiyong,?20052
回顾
Java 基本类是作为 AWT 的扩展而开发的
Swing 是 JFC 下的一组类,提供轻量级可视化组件,可用于创建美观的 GUI
Swing 容器有两类:顶级容器、中间容器
Swing标签既可以显示文本也可以显示图像
Swing文本组件
Swing中用于选择性输入的常用组件
菜单是 GUI中非常有用的一部分
Designed by Chiyong,?20053
目标
了解多线程的概念
掌握如何创建线程
了解死锁的概念
掌握线程同步
掌握使用 wait() 和 notify() 在线程之间进行通信
Designed by Chiyong,?20054
多任务处理
进程是指一种,自包容,的运行程序,有自己的地址空间 ;线程是进程内部单一的一个顺序控制流
基于进程的特点是允许计算机同时运行两个或更多的程序。
基于线程的多任务处理环境中,线程是最小的处理单位。
多任务处理有两种类型:
- 基于进程
- 基于线程
Designed by Chiyong,?20055
基于线程的多任务处理的优点
基于线程所需的开销更少
– 在多任务中,各个进程需要分配它们自己独立的地址空间
– 多个线程可共享相同的地址空间并且共同分享同一个进程
进程间调用涉及的开销比线程间通信多
线程间的切换成本比进程间切换成本低
Designed by Chiyong,?20056
多线程
多线程
– 在 Java中,一个应用程序可以包含多个线程。
每个线程执行特定的任务,并可与其他线程并发执行
– 多线程使系统的空转时间最少,提高 CPU利用率
– 多线程编程环境用方便的模型隐藏 CPU在任务间切换的事实
Designed by Chiyong,?20057
主线程
在 Java程序启动时,一个线程立刻运行,
该线程通常称为程序的主线程。
主线程的重要性体现在两个方面:
– 它是产生其他子线程的线程。
– 通常它必须最后完成执行,因为它执行各种关闭动作。
Designed by Chiyong,?20058
主线程示例
class Mythread extends Thread {
public static void main(String args[]) {
Thread t= Thread.currentThread();
System.out.println("当前线程是,"+t);
t.setName("MyJavaThread");
System.out.println("当前线程名是,"+t);
try {
for(int i=0;i<3;i++) {
System.out.println(i); Thread.sleep(1500);
}
}
catch(InterruptedException e) {
System.out.println("主线程被中断 "); }
}
}
获得当前线程,
即主线程改变线程的内部名称输出每个数后暂停 1500毫秒
Designed by Chiyong,?20059
创建线程 2-1
通过以下两种方法创建 Thread 对象:
声明一个 Thread 类的子类,并 覆盖 run() 方法。
class mythread extends Thread {
public void run( ) {/* 覆盖 该方法 */ }
}
声明一个实现 Runnable 接口的类,并实现 run()
方法。
class mythread implements Runnable{
public void run( ) {/* 实现该方法 */ }
}
Designed by Chiyong,?200510
创建线程 2-2
要触发一个新线程,使用 start() 方法,如:
Mythread t = new Mythread();
t.start();
在调用 start() 方法时,将创建一个新的控制线程,接着它将调用 run() 方法。
run() 方法中的代码定义执行线程所需的功能。
Designed by Chiyong,?200511
创建线程示例
class MyThread1 extends Thread {
public static void main(String args[]) {
Thread t= Thread.currentThread();
System.out.println("主线程是,"+t);
MyThread1 ex = new MyThread1();
ex.start();
}
public void run() {
System.out.println("子线程是,"+this);
}
}
或者使用
implements
Runnable
Designed by Chiyong,?200512
线程的状态 4-1
新建 (Born),新建的线程处于新建状态
就绪 (Ready),在创建线程后,它将处于就绪状态,等待 start() 方法被调用
运行 (Running),线程在开始执行时进入运行状态
睡眠 (Sleeping),线程的执行可通过使用
sleep() 方法来暂时中止。在睡眠后,线程将进入就绪状态
Designed by Chiyong,?200513
线程的状态 4-2
等待 (Waiting),如果调用了 wait() 方法,
线程将处于等待状态。用于在两个或多个线程并发运行时。
挂起 (Suspended),在临时停止或中断线程的执行时,线程就处于挂起状态。
恢复 (Resume),在挂起的线程被恢复执行时,可以说它已被恢复。
Designed by Chiyong,?200514
阻塞 (Blocked) – 在线程等待一个事件时(例如输入 /输出操作),就称其处于阻塞状态。
死亡 (Dead) – 在 run() 方法已完成执行或其
stop() 方法被调用之后,线程就处于死亡状态。
线程状态 4-3
Designed by Chiyong,?200515
线程的状态图挂起新线程(新建)
就绪运行死亡睡眠等待 阻塞
Designed by Chiyong,?200516
可能使线程暂停执行的条件
线程:
- 线程优先级比较低,因此它不能获得 CPU
时间。
- 使用 sleep( ) 方法使线程睡眠。
- 通过调用 wait( ) 方法,使线程等待。
- 通过调用 yield( ) 方法,线程已显式出让 CPU
控制权。
- 线程由于等待一个文件 I/O事件被阻塞。
Designed by Chiyong,?200517
线程状态的示例
class ThreadStateDemo extends Thread {
Thread t;
public ThreadStateDemo() {
t=new Thread(this);
System.out.println ("线程 t 为新建 ! ");
System.out.println ("线程 t 为就绪 ! ");
t.start();
}
public void run() {
try {
System.out.println ("线程 t 在运行 ! ");
t.sleep(500);
System.out.println("线程 t 在短时间睡眠后重新运行 ! ");
} catch (InterruptedException IE) {
System.out.println("线程被中断 ");
}
}
public static void main(String args[]) {
new ThreadStateDemo();
}
}
Designed by Chiyong,?200518
Thread 类中的重要方法 2-1
方法 用途
static int enumerate(Thread [ ] t) 将线程所在的线程组及其子组中所有活动的线程复制到指定数组中,返回线程的个数
final String getName( ) 返回线程的名称
final boolean isAlive() 如果线程是激活的,则返回 true
final void setName(String name) 将线程的名称设置为由 name指定的名称
final void join( ) throws
InterruptedException
等待线程结束
Designed by Chiyong,?200519
Thread 类中的重要方法 2-2
方法 用途
final boolean isDaemon( ) 检查线程是否为精灵线程
final void
setDaemon(boolean on)
根据传入的参数,将线程标记为精灵线程或用户线程
static void sleep( ) 用于将线程挂起一段时间
void start( ) 使线程进入就绪状态,将调用 run( )方法启动线程
static int activeCount( ) 返回激活的线程数
static void yield() 使正在执行的线程临时暂停,并允许其他线程执行
Designed by Chiyong,?200520
线程优先级
Java 中的线程优先级是在 Thread 类中定义的常量
- NORM_PRIORITY,值为 5
- MAX_PRIORITY,值为 10
- MIN_PRIORITY,值为 1
缺省优先级为 NORM_PRIORITY
有关优先级的方法有两个,
- final void setPriority(int newp),修改线程的当前优先级
- final int getPriority(),返回线程的优先级
Designed by Chiyong,?200521
线程同步
有时两个或多个线程可能会试图同时访问一个资源例如,一个线程可能尝试从一个文件中读取数据,而另一个线程则尝试在同一文件中修改数据
在此情况下,数据可能会变得不一致
为了确保在任何时间点一个共享的资源只被一个线程使用,使用了,同步,
Designed by Chiyong,?200522
如何在 Java 中获得同步
同步基于“监视器”这一概念。“监视器”是用作互斥锁的对象。在给定时刻,只有一个线程可以拥有监视器。
Java中所有的对象都拥有自己的监视器
两种方式实现同步:
– 使用同步方法
synchronized void methodA() { }
– 使用同步块
synchronized(object) {
//要同步的语句
}
Designed by Chiyong,?200523
同步方法
class One {
synchronized void display(int num) {
System.out.print(""+num);
try {
Thread.sleep(1000);
}
catch(InterruptedException e) {
System.out.println("中断 ");
}
System.out.println(" 完成 ");
}
}
进入某一对象的监视器,就是调用被 synchronized关键字修饰的方法 。
class Two implements Runnable {
int number;
One one;
Thread t;
public Two(One one_num,int n) {
one=one_num; number=n;
t=new Thread(this);
t.start();
}
public void run() {
one.display(number);
}
}
public class Synch {
public static void main(String args[]) {
One one=new One();
int digit=10;
Two s1=new Two(one,digit++);
Two s2=new Two(one,digit++);
Two s3=new Two(one,digit++);
s1.t.join();
s2.t.join();
s3.t.join();
}
}
Designed by Chiyong,?200524
同步块 如 果 无 法 在 相 关 方 法 前 加synchronized 修饰符,只需将对这个类定义的方法的调用放入一个
synchronized 块内就可以了 。
class One {
void display(int num) {
System.out.print(""+num);
try {
Thread.sleep(1000);
}
catch(InterruptedException e){
System.out.println("中断 ");
}
System.out.println(" 完成 ");
}
}
class Two implements Runnable {
int number;
One one;
Thread t;
public Two(One one_num,int n) {
one=one_num; number=n;
t=new Thread(this); t.start();
}
public void run() {
synchronized(one) {
one.display(number);
}
}
}
Designed by Chiyong,?200525
死锁
当两个线程循环依赖于一对同步对象时将发生死锁。例如:
一个线程进入对象 ObjA上的监视器,而另一个线程进入对象 ObjB上的监视器。如果 ObjA中的线程试图调用 ObjB上的任何 synchronized 方法,就将发生死锁。
死锁很少发生,但一旦发生就很难调试。
Designed by Chiyong,?200526
wait-notify 机制 2-1
为避免轮流检测,Java提供了一个精心设计的线程间通信机制,使用 wait(),notify()
和 notifyAll()方法 。
这些方法是作为 Object 类中的 final 方法实现的。
这三个方法仅在 synchronized 方法中才能被调用。
Designed by Chiyong,?200527
wait-notify 机制 2-2
wait()方法告知被调用的线程退出监视器并进入等待状态,直到其他线程进入相同的监视器并调用 notify( ) 方法。
notify( ) 方法通知同一对象上第一个调用
wait( )线程。
notifyAll() 方法通知调用 wait() 的所有线程,
具有最高优先级的线程将先运行。
Designed by Chiyong,?200528
使用 wait-notify 机制示例
class ChopStick {
boolean available;
ChopStick() { available=true; }
public synchronized void takeup() {
while(!available) {
try {
wait(); System.out.println("哲学家等待另一根筷子 ");
} catch(InterruptedException e) { }
}
available=false;
}
public synchronized void putdown() {
available=true;
notify();
}
}
Designed by Chiyong,?200529
总结 2-1
多线程允许程序员编写可最大程度利用 CPU
的高效程序。
Java 以类和接口的形式为多线程提供内置支持。
Java 程序启动时,一个线程立刻运行,该线程称为主线程。
可通过两种方式创建线程:继承 Thread类、
实现 Runnable 接口 。
Designed by Chiyong,?200530
总结 2-2
Thread 类 的有两个构造函数。
线程的缺省优先级为 5。
作为后台线程并为其他线程提供服务的线程称为精灵线程。
同步是用于确保资源一次只能被一个线程使用的过程。
wait-notify机制 用来处理线程间通信