Java之Thread浅谈
进程与线程
什么是进程?进程是操作系统结构的基础,是程序在一个数据集合上运行的过程,是系统进行资源分配和调度的基本单位。进程可以被看作程序的实体,同样,它也是线程的容器。
什么是线程?线程是操作系统调度的最小单元,也叫作轻量级进程。在一个进程中可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。
线程的状态
-
New:新创建的状态。线程被创建,还没有调用
start
方法,在线程运行之前还有一些基础工作要做。 -
Runnable:可运行状态。一旦调用
start
方法,线程就处于Runnable
状态。一个可运行的线程可能正在运行也肯能没有运行,这取决于操作系统给线程提供运行的时间。 - Blocked:阻塞状态。表示线程被锁阻塞,它暂时不活动。
- Waiting:等待状态。线程暂时不活动,并且不运行任何代码,这消耗最少资源,直到线程调度器重新激活它。
- Timed waiting:超时等待状态。和等待状态不同的是,它是可以在指定的时间自行返回的。
-
Terminated:终止状态。表示当前线程已经执行完毕。导致线程终止有两种情况:第一种就是
run
方法执行完毕正常退出;第二种就是因为一个没有捕获的异常而终止了run
方法,导致线程进入终止状态。
线程的简单应用
上面已经说过,线程有多种状态,那么为什么需要这几种状态?或者说哪些情况会进入到这些状态?下面我们举例说明。
- New新创建状态
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//do something...
}
});
System.out.println(thread.getState());
我们看打印的结果:Thread-0:NEW
,可以证明该线程处于New
状态。
- Runnable可运行状态
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
});
thread.start();
System.out.println(thread.getState());
首先看下打印的结果:Thread-0:RUNNABLE
。线程创建完成后我们调用start
方法,线程会进入Runnable
状态。
- Blocked阻塞状态
这里解释下什么叫阻塞状态?运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,该线程将进入阻塞状态,如下示例。
public class Thread9 {
static Object object = new Object();
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.setName("threadA");
threadB.setName("threadB");
threadA.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
threadB.start();
System.out.println(threadA.getName() + ":" + threadA.getState());
System.out.println(threadB.getName() + ":" + threadB.getState());
}
static class ThreadA extends Thread{
@Override
public void run() {
synchronized (object) {
while(true) {
}
}
};
}
static class ThreadB extends Thread{
@Override
public void run() {
synchronized (object) {
System.out.println("ThreadB");
}
};
}
}
打印结果:
threadA:RUNNABLE
threadB:BLOCKED
上面的例子中,开启两个线程A和B,A、B线程的run
方法中获取同一对象的同步锁,由于A线程一直持有Object对象,B线程的任务无法进行,会进入阻塞状态。当A线程任务完成或出现异常将不再持有该对象时,B线程将进入到Runnable
状态。
- Waiting等待状态
线程暂时不活动,并且不运行任何代码,调用
wait()
或join()
(实际上也是调用wait()
方法)方法可进入该状态,调用notify()
或notifyAll()
方法解除状态,示例如下。
调用
join()
方法
package thread;
public class JoinTest {
public static void main(String[] args) throws InterruptedException{
Thread1 thread1 = new Thread1();
thread1.setName("Thread-1");
thread1.start();
System.out.println("begin");
Thread.sleep(2000);
System.out.println(thread1.getName() + ":" + thread1.getState());
}
static class Thread1 extends Thread {
@Override
public void run(){
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread-2:running");
}
}
});
thread2.setName("Thread-2");
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end");
}
}
}
打印结果:
begin
Thread-2:running
Thread-1:WAITING
Thread-2:running
Thread-2:running
Thread-2:running
Thread-2:running
end
在线程1中再开启一个线程2,线程2开始后调用join()
方法,然后查看线程1的状态。
调用
wait()
方法
package thread;
import java.util.concurrent.TimeUnit;
public class WaitTest{
public synchronized void waittest() throws InterruptedException {
System.out.println("start");
wait();
System.out.println("over");
}
public synchronized void notifyTest() {
notifyAll();
}
public static void main(String[] args) throws InterruptedException{
WaitTest waitTest = new WaitTest();
Thread mainThread = Thread.currentThread();
MyThread myThread = new MyThread(mainThread,waitTest);
mainThread.setName("Thread-main");
myThread.setName("Thread-0");
myThread.start();
waitTest.waittest();
}
static class MyThread extends Thread{
Thread thread;
WaitTest waitTest;
public MyThread(Thread thread,WaitTest waitTest) {
this.thread = thread;
this.waitTest = waitTest;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(thread.getName()
+ ":" + thread.getState());
int i = 0;
do {
i++;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.currentThread().getName()
+ ":" + this.currentThread().getState());
} while (i < 5);
waitTest.notifyTest();
}
}
}
打印结果:
start
Thread-main:WAITING
Thread-0:RUNNABLE
Thread-0:RUNNABLE
Thread-0:RUNNABLE
Thread-0:RUNNABLE
Thread-0:RUNNABLE
over
开启一个新线程,然后主线程调用wait()
方法(必须使用同步字synchronized加锁,否则会报异常),查看主线程的状态。
通过上面两个示例我们可以看到,调用wait()
和join()
方法都可以使线程进入WAITING状态,但是它们两者是有区别的(它们的区别以后会讲到,这里就不详细比较了)。
- Timed waiting超时等待状态
Timed waiting和Waiting的不同之处在于,Timed waiting有时间限制,时间到了之后将自行解除该状态。
package thread;
public class TimeWaitIngTest {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadA threadB = new ThreadA();
ThreadA threadC = new ThreadA();
threadA.setName("thread-A");
threadB.setName("thread-B");
threadC.setName("thread-C");
threadA.start();
threadB.start();
threadC.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadA.getName()
+ ":" + threadA.getState());
System.out.println(threadB.getName()
+ ":" + threadB.getState());
System.out.println(threadC.getName()
+ ":" + threadC.getState());
}
static class ThreadA extends Thread{
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadB extends Thread{
@Override
public void run() {
try {
wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadC extends Thread{
@Override
public void run() {
try {
join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印结果:
thread-A:TIMED_WAITING
thread-B:TIMED_WAITING
thread-C:TIMED_WAITING
开启三个线程,分别调用sleep(long)
、wait(long)
和join(long)
方法,看这三个线程的状态。
- TERMINATED终止状态
package thread;
public class TerminatedTest {
public static void main(String[] args) throws InterruptedException{
MyThread myThread = new MyThread();
myThread.setName("MyThread");
System.out.println(myThread.getName()
+ ":" + myThread.getState());
myThread.start();
Thread.sleep(10);
System.out.println(myThread.getName()
+ ":" + myThread.getState());
}
static class MyThread extends Thread{
@Override
public void run() {
}
}
}
打印结果:
MyThread:NEW
MyThread:TERMINATED
新建一个线程,然后执行,看线程的状态变化。
综上所诉,线程一般有6种状态,下面用一张图来总结
线程状态