线程
一个独立程序的每一次运行称为一个进程;进程要占用相当一部分处理器时间和内存资源 ;进程具有独立的内存空间
Thread类
直接继承了Object类,并实现了Runnable接口。位于java.lang包中
封装了线程对象需要的属性和方法
继承Thread类——创建多线程的方法之一
从Thread类派生一个子类,并创建子类的对象
子类应该重写Thread类的run方法,写入需要在新线程中执行的语句段。
调用start方法来启动新线程,自动进入run方法。
如果启动新线程后希望主线程多持续一会再结束,可在start语句后加上让当前线程(这里当然是main)休息1毫秒的语句:
try { Thread.sleep(1); } catch(Exception e){};
常用API
名称 | 说明 |
public Thread() | 构造一个新的线程对象,默认名为Thread-n,n是从0开始递增的整数 |
Public Thread(Runnable target) | 构造一个新的线程对象,以一个实现Runnable接口的类的对象为参数。默认名为Thread-n,n是从0开始递增的整数 |
public Thread(String name) | 构造一个新的线程对象,并同时指定线程名 |
public static Thread currentThread() | 返回当前正在运行的线程对象 |
public static void yield() | 使当前线程对象暂停,允许别的线程开始运行 |
public static void sleep(long millis) | 使当前线程暂停运行指定毫秒数,但此线程并不失去已获得的锁旗标。 |
public void start() | 启动线程,JVM将调用此线程的run方法,结果是将同时运行两个线程,当前线程和执行run方法的线程 |
public void run() | Thread的子类应该重写此方法,内容应为该线程应执行的任务。 |
public final void stop() | 停止线程运行,释放该线程占用的对象锁旗标。 |
public void interrupt() | 中断此线程 |
public final void join() | 如果此前启动了线程A,调用join方法将等待线程A死亡才能继续执行当前线程 |
public final void join(long millis) | 如果此前启动了线程A,调用join方法将等待指定毫秒数或线程A死亡才能继续执行当前线程 |
public final void setPriority( int newPriority) | 设置线程优先级 |
public final void setDaemon(Boolean on) | 设置是否为后台线程,如果当前运行线程均为后台线程则JVM停止运行。这个方法必须在start()方法前使用 |
public final void checkAccess() | 判断当前线程是否有权力修改调用此方法的线程 |
public void setName(String name) | 更改本线程的名称为指定参数 |
public final boolean isAlive() | 测试线程是否处于活动状态,如果线程被启动并且没有死亡则返回true |
Runnable接口
Thread类实现了Runnable接口;只有一个run()方法;更便于多个线程共享资源;Java不支持多继承,如果已经继承了某个基类,便需要实现Runnable接口来生成多线程;以实现runnable的对象为参数建立新的线程;start方法启动线程就会运行run()方法
有时线程之间彼此不独立、需要同步
线程间的互斥
同时运行的几个线程需要共享一个(些)数据
共享的数据,在某一时刻只允许一个线程对其进行操作
“生产者/消费者” 问题
假设有一个线程负责往数据区写数据,另一个线程从同一数据区中读数据,两个线程可以并行执行
如果数据区已满,生产者要等消费者取走一些数据后才能再写
当数据区空时,消费者要等生产者写入一些数据后再取
线程同步
互斥:许多线程在同一个共享数据上操作而互不干扰,同一时刻只能有一个线程访问该共享数据。因此有些方法或程序段在同一时刻只能被一个线程执行,称之为监视区
协作:多个线程可以有条件地同时操作共享数据。执行监视区代码的线程在条件满足的情况下可以允许其它线程进入监视区
synchronized ——线程同步关键字,实现互斥
用于指定需要同步的代码段或方法,也就是监视区
可实现与一个锁旗标的交互。例如:synchronized(对象){ 代码段 }
synchronized的功能是:首先判断对象的锁旗标是否在,如果在就获得锁旗标,然后就可以执行紧随其后的代码段;如果对象的锁旗标不在(已被其他线程拿走),就进入等待状态,直到获得锁旗标
当被synchronized限定的代码段执行完,就释放锁旗标
互斥
Java 使用监视器机制
每个对象只有一个“锁旗标” ,利用多线程对“锁旗标”的争夺实现线程间的互斥
当线程A获得了一个对象的锁旗标后,线程B必须等待线程A完成规定的操作、并释放出锁旗标后,才能获得该对象的锁旗标,并执行线程B中的操作
将需要互斥的语句段放入synchronized(object){}语句中,且两处的object是相同的
java.lang.Object 类的一些方法为线程间的通讯提供了有效手段
wait() 如果当前状态不适合本线程执行,正在执行同步代码(synchronized)的某个线程A调用该方法(在对象x上),该线程暂停执行而进入对象x的等待池,并释放已获得的对象x的锁旗标。线程A要一直等到其他线程在对象x上调用notify或notifyAll方法,才能够在重新获得对象x的锁旗标后继续执行(从wait语句后继续执行)
notify() 随机唤醒一个等待的线程,本线程继续执行
线程被唤醒以后,还要等发出唤醒消息者释放监视器,这期间关键数据仍可能被改变
被唤醒的线程开始执行时,一定要判断当前状态是否适合自己运行
notifyAll() 唤醒所有等待的线程,本线程继续执行
死锁