线程简述
线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及部分运行时环境,具体可学习该文章:http://www.cnblogs.com/lmule/archive/2010/08/18/1802774.html 另外,关于线程与进程这里有一篇非常有意思的博客,供大家参考:http://www.ruanyifeng.com/blog/2013/04/PRocesses_and_threads.html多线程优势
进程之间不能共享内存,但线程之间共享内存/文件描述符/进程状态非常容易.
系统创建进程时需要为该其分配很多系统资源(如进程控制块),但创建线程的开销要小得多,因此线程实现多任务并发比进程效率高.
java语言内置多线程支持,而不是单纯采用底层操作系统API调用, 从而可以简化Java的多线程编程.
线程创建与启动
Java使用java.lang.Thread代表线程(所有的线程对象必须是Thread类的实例).使用java.lang.Runnable java.util.concurrent.Callable和java.util.concurrent.Future来代表一段线程执行体(一段顺序执行的代码).一个线程的作用是完成一段程序流的执行,同时子线程的执行还可以跟父线程并行, 两段线程的执行流程没有关系, 父线程还可以继续执行其他的事情.继承Thread
继承Thread类,并重写run()方法(代表线程执行体),然后调用start()方法来启动线程.public class ThreadExtendsThread { public static void main(String[] args) { new DemoThread().start(); new DemoThread("second").start(); for (int i = 0; i < 10; ++i) { System.out.println(Thread.currentThread().getName() + ": i"); } } private static class DemoThread extends Thread { public DemoThread() { } public DemoThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 10; ++i) { System.out.println(getName() + ": " + i); } } }}继承Thread类来创建线程类时,多个线程之间无法共享线程类的实例变量.
实现Runnable
实现Runnable接口,重写run()方法(同样代表线程执行体),并将该类实例作为Thread的target提交给线程执行.public class ThreadImplementsRunnable { public static void main(String[] args) { Runnable runnable = new DemoRunnable(); Thread threadA = new Thread(runnable, "first"); Thread threadB = new Thread(runnable); threadA.start(); threadB.start(); for (int i = 0; i < 10; ++i) { System.out.println(Thread.currentThread().getName() + " " + i); } } private static class DemoRunnable implements Runnable { private int i = 0; public void run() { for (; i < 10; ++i) { System.out.println(Thread.currentThread().getName() + " " + i); } } }} 运行上例可以看到i值重复的现象,这是因为有多个线程都在修改同一个i值, 对于并发修改共享资源的情况,需要添加同步机制保护,详见下面. Runnable对象仅作为Thread对象的target,其包含的run()方法仅作为线程执行体.实际的线程对象依然是Thread实例, 只是该Thread线程执行的是target的run()方法.Callable与Future
Callable接口提供一个call()方法作为线程执行体,相比于run(),call()可以有返回值,还可以声明抛出异常,但它并不是Runnable接口的子接口, 所以不能直接作为target执行。因此Java又提供了Future接口来代表Callable中call()方法的返回值,并提供java.util.concurrent.FutureTask类实现Callable与Runnable接口(其实现了RunnableFuture接口,该接口同时继承了Runnable、 Future),以作为Thread的target。Callable创建并启动线程的步骤如下: • 实现Callable接口并重写call()方法; • 使用FutureTask类包装Callable对象; • 将FutureTask实例提交给Thread并启动新线程; • 使用FutureTask的get()获取子线程执行结束后的返回值.
public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { RunnableFuture<Integer> task = new FutureTask<Integer>(new DemoCallable()); new Thread(task).start(); while (true) { System.out.println("The main thread doing something ..."); if (task.isDone()) { System.out.println("The child thread return: " + task.get()); break; } Thread.sleep(5); } } private static class DemoCallable implements Callable<Integer> { public Integer call() throws Exception { int total = 0; for (int i = 0; i < 100; ++i) { Thread.sleep(10); total += i; } return total; } }} 由于实现Runnable和Callable的方式可以让多个线程共享同一个target,因此适用于多个线程处理同一份资源的情况,从而将CPU/代码/数据分开.线程生命周期
当线程被new出并start后,他既不是马上就进入执行状态, 也不会一直处于执行状态, 一个线程会经过新建NEW -> 就绪RUNNABLE -> 运行RUNNING -> 阻塞BLOCKED -> 死亡DEAD五种状态切换.新建New 当new出一个Thread后,该线程处于新建状态,此时他和其他Java对象一样,仅由JVM为其分配内存.并没有表现出任何线程的动态特征.
就绪Runnable
当线程对象调用start()后,该线程处于就绪状态,JVM会为其创建方法调用栈(Stack Trace)/线程控制块/程序计数器(PC),处于这个状态的线程表示是可以运行的.但何时运行,取决于JVM里线程调度器的调度.运行Running
如果处于就绪状态的线程一旦获得了CPU,就开始执行run()方法中的线程执行体,则线程进入运行状态.
阻塞Blocked
当发生如下情况时,线程会进入阻塞状态
线程调用sleep()主动放弃处理器;线程调用阻塞IO, 其IO资源未到;线程试图获得同步监视器, 但同步监视器被其他线程持有;线程等待某个通知wait();调用了线程的suspend()方法(该方法将导致线程挂起,但这样容易导致死锁,不建议使用[详细见线程同步]).当前线程被阻塞之后, 其他线程就可以获得执行的机会. 当发生如下情况, 线程可以解除阻塞, 重新进入就绪:
线程sleep()到达指定时间;阻塞IO返回;成功获得同步监视器;线程收到了其他线程发出的通知notify();被suspend()的线程被调用了resume()恢复方法;被阻塞的线程会在合适的时候重新进入就绪状态.线程死亡
run() / call()方法执行完成, 线程正常结束; 线程抛出未捕获的Exception或Error; 直接调用线程的stop()方法结束该线程(该方法容易导致死锁,不建议使用).一旦子线程启动起来后,就拥有和父线程相同的地位,不会受父线程的任何影响(因此当主线程结束时,其他线程不会同主线程一起结束)为了测试某个线程是否生存, 可以调用Thread实例的isAlive()方法(就绪/运行/阻塞返回true, 新建/死亡返回false).
不要试图对已经死亡的线程调用start()方法, 死亡线程将不可再次作为线程执行.否则会抛出java.lang.IllegalThreadStateException.新闻热点
疑难解答