概念
线程
线程(thread)是操作系统能够进行运行调度的最小单位 。他被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序 的控制流,一个进程中可以并行多个线程,每条线程并行执行不同任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
自己的理解: 线程是进程的组成部分,它代表了一条顺序的执行流,他是cpu调度和分派的基本单位,基本上不占有什么系统资源(程序计数器,一组寄存器和栈还是会占用的),但是他可以与同一个进程下的其他线程共享进程的所有资源
线程共享资源 | 线程独享资源 |
---|---|
地址空间 | 程序计数器 |
全局变量 | 寄存器 |
打开的文件 | 栈 |
子进程 | 状态字 |
闹铃 | |
信号及信号服务程序 | |
记账信息 |
从线程这边插入一个堆栈概念
一个进程中的所有线程共享该进程的地址空间,但它们有各自独立的(/私有的)栈(stack),Windows线程的缺省堆栈大小为1M。堆(heap)的分配与栈有所不同,一般是一个进程有一个C运行时堆,这个堆为本进程中所有线程共享,windows进程还有所谓进程默认堆,用户也可以创建自己的堆。
用操作系统术语,线程切换的时候实际上切换的是一个可以称之为线程控制块的结构(TCB?),里面保存所有将来用于恢复线程环境必须的信息,包括所有必须保存的寄存器集,线程的状态等。
堆: 是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。
栈:是个线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是 thread safe的。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。
多线程
多线程指在单个程序中可以同时运行多个不同的线程执行不同的任务。
线程的实现方式
- Runnable
public class Thread02 implements Runnable {
public static void main(String[] args) {
new Thread(new Thread02()).start();
}
@Override
public void run() {
System.out.println("-----------实现方式1----------");
}
}
- Thread
public class Thread01 extends Thread{
public static void main(String[] args) {
Thread01 thread01 = new Thread01();
thread01.start();
}
@Override
public void run() {
System.out.println("-----------实现方式2-----------");
}
}
- Callable&Future(jdk1.5之后才有的)
public class Thread03 implements Callable<String> {
@Override
public String call() throws Exception {
return "------实现方式3------";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask task = new FutureTask(new Thread03());
new Thread(task).start();
System.out.println(task.get());
}
}
//源码时刻 :
//1.
public class FutureTask<V> implements RunnableFuture<V> {.....}
//2.
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
//3.FutureTask类下
重点是volatile修饰的state volatile 修饰的词能保证变量可见性、禁止重排序,但是不保证他的原子性
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
构造器
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
run()方法 UNSAFE是sun.misc下的,不部分方法用native修饰 CAS底层就是通过他实现的
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call(); //这是就开始调用Callable.call()方法
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);//还是cas操作
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
//4. set/ get方法
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);//阻塞 ,方法里的 LockSupport.parkNanos(this, nanos); 再深一点 自己翻阅
return report(s);
}
线程生命周期
以下是摘自java package目录 java.lang.Thread中枚举state中的值 ,中文注释为自己添加
源码如下:
public enum State {
/**
* Thread state for a thread which has not yet started.
*说明: 初始状态,线程被构建,但是还没有被调用start()方法
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*
* 说明:运行状态: java线程将操作系统中的就绪和运行两种状态笼统的 城作为“运行中”
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*
* 说明:阻塞状态,表示线程被锁阻塞
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*
* 说明: 等待状态,表示线程进入等待状态,进入改状态表示当前线程需要等待其他线程做出一些特定动作(通知,中断)
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*
* 说明:超时等待状态:该状态不同于WAITING,它是可以在指定的时间自行返回的
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*
* 说明: 终止状态,表示当前线程已经执行完毕
*/
TERMINATED;
}
以下版本是网上描述的五种状态 :
状态名称 | 说明 |
---|---|
新建状态(NEW) | 当程序使用 new 关键字创建了一个线程之后,该线程就处于新建状态,此时仅由 JVM 为其分配内存,并初始化其成员变量的值 |
就绪状态(RUNNABLE) | 当线程对象调用了 start()方法之后,该线程处于就绪状态。Java 虚拟机会为其创建方法调用栈和程序计数器,等待调度运行。 |
运行状态(RUNNING) | 如果处于就绪状态的线程获得了 CPU,开始执行 run()方法的线程执行体,则该线程处于运行状态。 |
阻塞状态(BLOCKED) | 阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得 cpu timeslice 转到运行(running)状态。阻塞的情况分三种,请看表格下方内容 |
线程死亡(DEAD) | 线程会以下面三种方式结束,结束后就是死亡状态。正常结束1. run()或 call()方法执行完成,线程正常结束。异常结束2. 线程抛出一个未捕获的 Exception 或 Error。调用 stop3. 直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用。 |
阻塞的三种状态
- 等待阻塞(o.wait->等待对列):
运行(running)的线程执行 o.wait()方法,JVM 会把该线程放入等待队列(waitting queue)
中。
- 同步阻塞(lock->锁池)
运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线
程放入锁池(lock pool)中。
- 其他阻塞(sleep/join)
运行(running)的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时,
JVM 会把该线程置为阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O
处理完毕时,线程重新转入可运行(runnable)状态。
保证线程执行顺序 (join)
Thread thread1 = new Thread(()->{
System.out.println("------- 1 -------");
});
Thread thread2 = new Thread(()->{
System.out.println("------- 2 -------");
});
Thread thread3 = new Thread(()->{
System.out.println("------- 3 -------");
});
//不能保证执行顺序
// thread1.start();
// thread2.start();
// thread3.start();
//能保证执行顺序
thread1.start();
thread1.join();
thread2.start();
thread2.join();
thread3.start();
thread3.join();
join源码分析
//1 .
public final void join() throws InterruptedException {
join(0);
}
//2.
public final synchronized void join(long millis) //synchronized 修饰 独占式的悲观锁
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {//判断是否挂掉
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
//3.
public final native void wait(long timeout) throws InterruptedException;//他是一个native的本地方法
源码中注释: The current thread must own this object's monitor. 了解一下 当前线程必须拥有此对象的监视器。
注:Join中的wait方法 并不是说针对于子线程的 而是主线程 ,在这里你可以理解为main方法为主线程, thread1,thread2,thread3为子线程