多线程
概念
多任务处理有两种类型:
- 基于进程
- 基于线程
进程是指一种“自包容”的运行程序,有自己的地址空间;
线程是进程内部单一的一个顺序控制流
基于进程的特点是允许计算机同时运行两个或更多的程序。
基于线程的多任务处理环境中,线程是最小的处理单位。
基于线程所需的开销更少
在多任务中,各个进程需要分配它们自己独立的地址空间
多个线程可共享相同的地址空间并且共同分享同一个进程
进程间调用涉及的开销比线程间通信多
线程间的切换成本比进程间切换成本低
可以将在一个Java虚拟机中运行的多线程程序看成是一个操作系统中
运行的多个进程。
创建和启动线程
通过以下两种方法创建 Thread 对象:
- 声明一个 Thread 类的子类,并覆盖 run() 方法。
class mythread extends Thread {
public void run( ) {
/* 覆盖该方法*/
}
}
- 声明一个实现 Runnable 接口的类,并实现 run() 方法。
class mythread implements Runnable{
public void run( ) {
/* 实现该方法*/
}
}
继承Thread类
public class TwoThread extends Thread {
public void run() {
for ( int i = 0; i < 10; i++ ) {
System.out.println("New thread");
}
}
public static void main(String[] args) {
TwoThread tt = new TwoThread();
tt.start();
for ( int i = 0; i < 10; i++ ) {
System.out.println("Main thread");
}
}
}
实现runnable接口
class MyThread implements Runnable {
int count;
Thread thrd;
MyThread(String name) {
thrd = new Thread(this, name);
count = 0;
thrd.start();
}
public void run() {
System.out.println(thrd.getName() + " starting.");
try {
do {
Thread.sleep(500);
System.out.println("In " + thrd.getName() +", count is " + count);
count++;
} while(count < 10);
}catch(InterruptedException exc) {
System.out.println(thrd.getName() + " interrupted.");
}
System.out.println(thrd.getName() + " terminating.");
}
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
}
}
线程的状态
暂停线程的条件
线程:
线程优先级比较低,因此它不能获得 CPU 时间。
使用 sleep( ) 方法使线程睡眠。
通过调用 wait( ) 方法,使线程等待。
通过调用 yield( ) 方法,线程已显式出让CPU控制权。
线程由于等待一个文件I/O事件被阻塞。
线程优先级
Java 中的线程优先级是在 Thread 类中定义的常量
NORM_PRIORITY : 值为 5
MAX_PRIORITY : 值为 10
MIN_PRIORITY : 值为 1
缺省优先级为 NORM_PRIORITY
有关优先级的方法有两个:
final void **setPriority(int newp) **: 修改线程的当前优先级
final int getPriority() : 返回线程的优先级
线程同步
有时两个或多个线程可能会试图同时访问同一个资源
例如,一个线程可能尝试从一个文件中读取数据,而另一个线程则尝试在同一文件中修改数据
在此情况下,数据可能会变得不一致
为了确保在任何时间点一个共享的资源只被一个线程使用,使用了“同步”
使用同步关键字synchronized来进行标识
同步方法
class One {
synchronized 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(0);
}
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++);
}
}
同步块
如果无法在相关方法前加synchronized 修饰符,只需将对这个类定义的方法的调用放入一个synchronized 块内就可以了。
class One {
synchronized 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);
}
}
}
死锁
当两个线程循环依赖于一对同步对象时将发生死锁。例如:
一个线程进入对象ObjA上的监视器,而另一个线程进入对象ObjB上的监视器。如果ObjA中的线程试图调用ObjB上的任何 synchronized 方法,就将发生死锁。
死锁很少发生,但一旦发生就很难调试。
线程间通讯
synchronized 关键字阻止并发更新一个对象,但它没有实现线程间发信。
wait-notify 机制
为避免轮流检测,Java提供了一个精心设计的线程间通信机制,使用wait()、notify()和notifyAll()方法 。
这些方法是作为 Object 类中的 final 方法实现的。
这三个方法仅在 synchronized 方法中才能被调用。
- wait()方法告知被调用的线程退出监视器并进入等待状态,直到其他线程进入相同的监视器并调用** notify( ) **方法。
- notify( ) 方法通知同一对象上第一个调用 wait( )线程。
- notifyAll() 方法通知调用 wait() 的所有线程,具有最高优先级的线程将先运行。
通讯
实现线程之间通信的三个方法是
- wait()
- notify()
- notifyAll()