java的多线程编程中涉及的东西比较多,本文主要从线程的概述、线程、进程与线程的区别、线程的状态以及切换
概述
1、线程是操作系统的概念,是进程的一个执行单元(通俗的讲就是进程的执行线路,一个进程至少有一个线程)。
2、在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。
3、后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。 —— [ 编程思想之多线程与多进程(1)——以操作系统的角度述说线程与进程 ]
为什么要引入线程:
提高系统的并发性,有效的使用系统的资源和提高系统的吞吐量(单位时间内执行的指令数)
进程和线程的区别
比较 | 线程 | 进程 |
---|---|---|
调度 | CPU调度和分配的基本单位 | CPU资源分配的基本单位 |
并发性 | 进程与进程可以并发执行,进程下线程与线程也可以并发执行 | 进程与进程之间并发执行,若某进程服务被锁,便没有该进程的服务可提供服务了 |
系统开销 | 开销小(线程切换只需要保存少量的寄存器和内容,不涉及存储器管理方面,同一进程中,若线程有相同的地址空间,同步和通信容易,有的操作系统,同步和通信不需要系统内核干预) | 开销大(旧CPU环境的保存和设置,新CPU环境的保存和设置) |
拥有资源 | 线程不拥有系统资源,但是可以访问其隶属的进程资源。(也就是同一进程的代码段、数据段、以及系统资源可供同一进程的其他线程共享) | 进程拥有系统资源的独立单位 |
进程与线程的关系图
线程间的状态
一、操作系统分析线程间的状态
线程的生命周期
创建:一个新的线程被创建,等待该线程被调用执行;
就绪:时间片已用完,此线程被强制暂停,等待下一个属于他的时间片到来;
运行:此线程正在执行,正在占用时间片;
阻塞:也叫等待状态,等待某一事件(如IO或另一个线程)执行完;
退出:一个线程完成任务或者其他终止条件发生,该线程终止进入退出状态,退出状态释放该线程所分配的资源。
二、从java分析线程间的状态(java1.5以后的源码):
/**
* A thread state. A thread can be in one of the following states:
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
*
* <p>
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
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.
*/
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>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
线程状态
(1)NEW(新建尚未运行/启动)
(2)RUNNABLE(处于可运行状态:正在运行或准备运行)
(3)BLOCKED(等待获取锁时进入的状态)
(4)WAITING(通过wait方法进入的等待)
(5)TIMED_WAITING(通过sleep或wait timeout方法进入的限期等待的状态)
(6)TERMINATED(线程终止状态)
(1)NEW(新建尚未运行/启动)
还没调用start,或者调用了start()方法,不一定立即改变线程状态,中间可能需要一些步骤才完成一个线程的启动。
Thread t = new Thread();
System.out.println(t.getState());//输出NEW
(2)RUNNABLE(处于可运行状态:正在运行或准备运行)
start调用结束,线程由NEW变成RUNNABLE,存活着,并尝试占用CPU资源,yield操作时,线程还是Runnable状态,只是它有一个细节的内部变化,做一个简单的让步。在Java层面是Runnable的状态,并不代表一定处于运行中的状态,比如BIO中,线程正阻塞在网络等待的时候,看到的状态依然是Runnable状态,而底层线程已经被阻塞住了。
Thread t = new Thread(){
public void run(){
for(int i=0; i< 10000; i++){
System. out.println(i);
}
}
};
t.start();
System.out.println(t.getState());//输出RUNNABLE
(3)BLOCKED(两个线程,相互等待Synchronized)
线程被挂起了,原因通常是因为它在等待一个锁,当某个synchronized正好有线程在使用时,一个线程尝试进入这个临界区,就会被阻塞,直到另一个线程走完临界区或发生了相应锁对象的wait操作后,它才有机会去争夺进入临界区的权利。当抢到锁之后,才会从blocked状态恢复到runnable状态。这个状态它好像什么也不做一样。
final Object lock = new Object();
Runnable run = new Runnable() {
@Override
public void run() {
synchronized (lock) {
for(int i=0; i<1000; i++){
System.out.println(Thread.currentThread().getName()+"= "+i);
}
}
}
};
Thread t1 = new Thread(run);
t1.setName("t1");
Thread t2 = new Thread(run);
t2.setName("t2");
t1.start();
t2.start();
System.out.println("t1"+t1.getState());
System.out.println("t2"+t2.getState());
(4)WAITING(通过wait方法进入的等待)
当wait,join,park方法调用时,进入waiting状态。前提是这个线程已经拥有锁了。
final Object lock = new Object();
Thread t1 = new Thread(){
@Override
public void run() {
int i = 0;
while(true ){
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
}
System.out.println(i++);
}
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
while(true ){
synchronized (lock) {
for(int i = 0; i< 100; i++){
System.out.println(i);
}
lock.notifyAll();
}
}
}
};
t1.setName( "^^t1^^");
t2.setName( "^^t2^^");
t1.start();
t2.start();
System.out.println("t1"+t1.getState());
System.out.println("t2"+t2.getState());
线程进入waiting的三种方法:
调用Object.wait()且没有超时
调用Thread.join()且没有超时
调用LockSupport.park(Object)
Java千百问01基本概念(007)线程的状态有哪些
唤醒waiting线程的方法:
1、一个线程执行Object.wait()
2、另一个线程调用对象Object.notify()==唤醒一个处于wait线程
Object.notifyAll()==唤醒所有处于wait等待的线程。
blocked和waiting状态的区别是:
A、blocked是虚拟机认为程序还不能进入某个区域(临界区),它要求同一个时刻只能有一个线程进去,另外一个线程就处于blocked状态,blocked状态的线程正在等待获取锁。
B、发生wait等操作的先决条件是线程已经拿到锁,进入临界区,并且执行了一些事情,但执行某段程序时某些业务上的参数或者资源不满足,必须等待另外一个线程执行完后才满足,并唤醒该线程继续执行之后的代码。(也就是一个线程无限期的等待另外一个线程来唤醒)。
在waiting状态下,如果发生了interrupt操作,则处于该状态的线程在内部会抛出一个InterruptedException,这个异常应当在run方法内捕获,使得run方法正常地执行完成,当然捕获异常后,是决定让线程继续运行,还是结束等要根据业务场景才处理。
(5)TIMED_WAITING(通过sleep或wait timeout方法进入的限期等待的状态)
线程进入TIMED_WAITING的方法:
调用Thread.sleep()
调用Object.wait()超过时间阈值
调用Thread.join()超过时间阈值
调用LockSupport.parkNanos(Object,long)
调用LockSupport.parkUntil(Object,long)
当时间达到时触发线程回到工作状态Runnable。interrupt只对处于waiting或timed_waiting状态的线程起作用,对其他状态不起作用。这个仅需要在4的基础上, 在wait方法加上一个时间参数进行限制,把4中的synchronized 块改成如下就可以了.
synchronized (lock) {
try {
lock.wait(60 * 1000L);
} catch (InterruptedException e) {
}
System.out.println(i++);
}
(6)TERMINATED(线程终止状态)
线程结束了,就处于这种状态,也就是run方法运行完了。这只是Java语言级别的一种状态,在操作系统内部可能已经注销了相应的线程,或者将它复用给其他需要使用线程的请求。
Thread t1 = new Thread();
t1.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
}
System.out.println(t1.getState());