多线程编程技术 (1)
辽宁经济职业技术学院信息系
硕士、副教授 陈英
序言
随着计算机技术的飞速发展,个人计算机上
的操作系统也纷纷采用多任务和分时设计。
将早期只有大型计算机才具有的系统特性,
带给了个人计算机。
一个进程就是一个执行中的程序,而每一个
进程都有自己独立的一块空间、一组系统资
源。
一般在同一时间内执行多个程序的操作系统,
都有进程的概念。
使用多任务运行特性时,仿佛是在同一个时
间内运行多个程序。
序言
多线程程序扩展了多任务操作的概念,它将
多任务操作降低一级来运行,那就是各个程
序似乎是在同一个时间内执行多个任务。
每个任务通常称为一个线程,它是控件的线
程的简称。能够同时运行多个线程的程序称
为多线程程序。
每个进程都有它自己的一组完整的变量,而
线程则共享相同的数据。
目前,所有最新的操作系统都支持多线程运
行。
单线程
多线

线程 1
读块 1 计算 1 写入 1 读块 2 计算 2 写入 2
读块 1 计算 1 写入 1
读块 2 计算 2 写入 2
读块 3 计算 3 写入 3
线程 1 线程 2 线程 3
时间
从一个文件中读取许多代码块
对每一块数据执行一些计算
把计算结果写入另一个文件


理解线程
理解线程 —— 多线程
线程 1
读块 1 计算 1 写入 1 读块 4 计算 4
读块 5读块 2 计算 2 写入 2
读块 3 计算 3 写入 3
线程 2
线程 3
时间
理解线程
Java程序通过流控制来执行程序流,程序中
单个顺序的流控制称为线程。
多线程指的是在单个程序中可以同时运行多
个不同的线程以执行不同的任务。
多线程的优势,
1) 减轻编写交互频繁、涉及面多的程序的困难。
2) 程序的吞吐量会得到改善,
3) 由多个处理器的系统,可以并发运行不同的线程。
(否则,任何时刻只有一个线程在运行。 )
线程与进程的区别
进程是正在执行的程序。
一个或更多的线程构成了一个进程。
多个进程的内部数据和状态都是完全独立
的,而多线程是共享一块内存空间和一组系
统资源,有可能互相影响,
线程本身的数据通常只有寄存器数据,以
及一个程序执行时使用的堆栈,所以线程
的切换比进程切换的负担要小。
一个线程由三个主要部分组成。
线程的构成
虚拟 CPU封装在 java.long.Thread的类中。
虚拟 CPU执行的代码,传递给 Thread的类。
虚拟 CPU处理的数据,传递给 Thread的类。
CPU
处理机
代码 数据
一个虚拟
处理机
理解线程
对线程的综合支持是 Java技术的一个重要
特色 。 它提供了 thread类, 监视器和条件
变量的技术 。
在 Java 编程中, 虚拟处理机封装在
Thread类的一个实例里 。 构造线程时,
定义其上下文的代码和数据是由传递给它
的构造函数的对象指定的 。
创建多线程
public class mythread extends Applet implements
Runnable
(小应用或已经是某个类的子类时 )
继承类 Thread
public class mythread extends Thread
实现 Runnable更符合面向对象的设计
1) 单继承
2) 一致性
扩展 Thread代码更简单
Thread类自身实现了
Runnable接口, 所以
可以通过扩展 Thread
类 而 不 是 实 现
Runnable来创建线程 。
创建多线程
上述两种方法中都可用类 Thread产生线程的对象
Thread newthread;
创建并启动线程
newthread=new Thread(this);
newthread.start();
run方法是运行线程的主体,启动线程时由 java直
接调用 public void run()
一个 Thread类构造函数带有一个参数,它是
Runnable的一个实例。一个 Runnable是由一个实
现了 Runnable接口 (即提供了一个 public void run()
方法 )的类产生的。
创建多线程
public class ThreadTest {
public static void main(String args[]) {
Xyz r = new Xyz();
Thread t = new Thread(r);
t.start();}}
class Xyz implements Runnable {
int i;
public void run() {
while (true) {
System.out.println("Hello " + i++);
if (i == 50) break;
}
} }
main()方法构
造了 Xyz类的
一个实例 r。
实例 r有它自
己的数据,在
这里就是整数
i。因为实例 r
是传给
Thread的类
构造函数的,
所以 r的整数 i
就是线程运行
时刻所操作的
数据。
创建多线程
线程总是从它所装载的 Runnable实例 (在
本例中这个实例就是 r)的 run()方法开始
运行。
一个多线程编程环境允许创建基于同一
个 Runnable实例的多个线程。这可以通
过以下方法来做到:
1) Thread t1= new Thread(r);
2) Thread t2= new Thread(r);
此时,这两个线程共享数据和代码。
创建多线程
Instance,r” of Xyz
CPU
Code Data
New thread
Thread t = new
Thread(r)
class Xyz implements
Runnable
线程通过
Thread对象的
一个实例引用
生成线程
你的程序总是至少会有一个线程:即当程序开
始执行的时候生成的线程。
1) 对于一般的程序,此线程从 main() 开始。
2) 对于 applet,浏览器就是主线程。
生成额外的线程涉及到使用 java.long.Thread类。
生成的每个额外的线程,都由 Thread类的一个
对象表示,或者由 Thread的一个子类表示。
在一个程序中除了主线程之外的线程总是从表
示该线程对象的 run()方法开始。 run()方法包
含着用于线程执行的代码。
守护程序和用户线程
守护线程 (daemon thread)就是一个后台运行的线
程,从属于生成它的线程。当生成这个守护线程
的线程结束时,这个守护线程也会随之消失。
设置守护线程的方法,setDaemon(true)
不是守护线程的线程称为用户线程 (user thread)。
在有限时间中运行的线程一般都是用户线程。一
个用户线程有自己的生存期,与生成它的线程无
关。所以当生成它的线程结束之后它仍然可以继
续执行。
包含 main()的默认线程是一个用户线程。
停止一个线程
停止线程由小应用程序的 stop调用线程的 stop
newthread.stop()
sleep方法的作用是暂停线程的执行,让其它线程
得到机会。 sleep要丢出异常,必须抓住。
Try{sleep(100)}catch(InterruptedException e){}
一个线程可以通过调用该 Thread对象的
interrupt()方法给另一个线程发送信号说它应该
停止。这样做本身不一定会停止该线程,而只是
在该线程中设置一个标记,以便于在 run()方法中
运行时被检查到,从而生效。
连接线程
如果需要在一个线程中等待,直到另一
个线程消失,可以调用该线程的 join()
方法,但等待时间不会太长。
如果不带参数调用 join()方法,将停止
当前的线程直到指定的线程消失。
Thread1.join();
也可以向 join()方法传递一个 long值,指
定你准备为一个线程的消失而等待时间
的毫秒数:
Thread1.join(1000);
线程的调度
线程的调度在一定程度上取决于你的操
作系统,但每个线程肯定会在其他线程
“休眠”的时候执行,也就是当他们调
用自己的 sleep()方法的时候。
如果操作系统使用的是抢先式多任务处
理,如 Windwos98,该程序不需要在
run()方法中调用 sleep()而运行。
thread1 thread2 thread3 thread4
Thread2
Sleep()
Thread1
Sleep()
Thread1
Sleep()
Thread3
Sleep()
Thread4
Sleep()
时间
阴影区表示各线程执行的时刻
线程状态的变迁
创建 可运行
运行中
死亡
等待阻塞
互斥阻塞
其他阻塞
不可运行
Notify()
Intrerup()wait()
synchronized
或 join()
interrupt()
sleep()
start()
yield()
运行结束
调度 时间到 join()
sleep()
获得互斥使用权