一. 线程的创建方式
1.1继承Thread类
重写run()方法即可。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread is running!");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
1.2实现Runnable接口
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable is running");
}
public static void main(String[] args) {
Thread myRunnable = new Thread(new MyRunnable());
myRunnable.start();
}
}
2 线程的5个状态
新建
当用new操作符创建一个线程对象后,如new Thread(r),还没有调用start()方法之前的状态
可运行
调用start()方法之后且没有被阻塞,也没在等待某个条件。可能正在运行也可能没有运行(等待CPU时间片)。在CPU分配时间片给多个线程,使它们轮流执行的过程中,不过实际有没有运行都处于可运行状态。
阻塞
当一个线程视图获取一个内部对象锁(synchronized),而该锁被其它线程持有,则该线程进入阻塞状态。内部对象锁是使用monitor对象实现的,每个monitor维持两个队列,一个是entry_list,一个wait_list。分别用于保存想获取锁的线程和等待条件的线程。(wait_list中的线程处于等待态)。
等待
等待一个条件时。1.Object.wait方法,进入wait_list队列,等待调用Object.notify()或Object.notifyAll()方法。2.等待ReentryLock或Condition时。3.调用Thread.join()方法
计时等待
有几个方法有一个超时参数。调用它们导致线程进入计时等待状态。这一状态将一直保持到超时期满或者接收到适当的通知。
这些方法有:Thread.sleep,Object.wait、Thread.join、Lock.tryLock、Condition.await等方法的计时版。
终止
线程因两个原因之一被终止
- 因为run方法正常退出而自然结束
- 因为一个没有捕获的异常终止了run方法而意外死亡
3 Object类中线程相关的方法
3.1 wait()方法
线程调用一个对象的wait()方法之前需要先获取到这个对象的内部对象锁,否则会抛出IllegalMonitorStateException异常。另一个可能的异常是:InterruptedException
调用这个方法使线程进入等待状态,在对象monitor对象的等待队列里默默等待,别的线程调用notify()或notifyAll()方法来唤醒。并且会释放获取到当前对象的锁。
这个方法常常用来等待某个条件的满足:
synchronized(obj) {
while(条件不满足) {
obj.wait()
}
//满足条件了,尽情干想干的事吧!
}
它还有个带计时的版本wait(long timeout),这是个native方法,是wait的真正实现。其实wait的实现就是调用了wait(0)而已。
3.2 notify()方法
和wait()方法配合使用。随机唤醒在对象monitor等待队列中一个线程。
同样需要先获取内部对象锁才能调用,否则会抛出IllegalMonitorStateException异常。
唤醒只是将线程从等待态切换到Runnable(可运行)态,不一定保证能立马执行(还有CPU分配时间片的因素)
调用此方法不会释放内部对象锁。
3.3 notifyAll()
唤醒所有的等待线程。
调用此方法需要先获取内部对象锁。
调用此方法不会四方内部对象锁。
4 Thread类中线程相关的方法
4.1 sleep(long millis)方法
方法声明:
public static native void sleep(long millis) throws InterruptedException;
是个静态方法,通过Thread.sleep()调用。使当前线程休眠指定时间再进入runnable状态。调用后进入阻塞态,不会释放内部对象锁。
4.2 join()方法
方法声明:
public final void join() throws InterruptedException ;
当前线程调用指定线程的join()方法,会等待该线程结束后再继续执行。
join方法还有一个带参数的版本,等待线程结束或到达指定时间再继续执行。
调用join后进入阻塞状态,不在执行join()语句之后的代码,直到该线程结束时this.notifyAll()方法会被调用,这时等待的线程就进入运行态。
4.3 yield()方法
方法声明:
public static native Thread currentThread();
可以从声明中看出这是一个静态方法,需要通过Thread.yield()来调用。
调用这个方法的线程主动让出CPU时间,从执行态转入就绪态,等待CPU的下次时间片。是一种主动放弃CPU执行的机制,但不会阻塞当前线程。也不释放锁。
4.4 interrupt()
此操作会中断等待中的线程,并将线程的中断标志位置位。但如果线程正在运行则不会受影响。可以通过以下三种方法来判断或重置中断位。
- isInterrupted 会读取中断位,并不会重置
- interrupted 读取中断位,并重置
- throw InterruptException 抛出异常的同时,会重置中断标志位
Java并发之基础知识
Java并发之volatile关键字
Java并发之synchronized关键字
Java并发之原子类
Java并发之线程池
Java并发之并发工具类
Java并发之AQS原理
Java并发之ThreadLocal使用和源码分析