您的位置:首页 > 编程语言 > Java开发

JDK源码学习(7)-Thread、Runnable与Callable

2016-06-30 11:07 603 查看
一、线程的基本概念
JAVA Thread代码中的状态枚举代码为:
public enum State {
//初始化Thread后但是未启动
NEW,

//就绪状态的线程,但是也有可能因为来自操作系统的某些原因造成等待,随时等待CUP进行调用。调用了start方法,也不一定马上就能运行。
RUNNABLE,

//阻塞状态,运行中的线程因为原因造成了阻塞,直到进入就绪状态,才能被CPU重新调用。
BLOCKED,

//等待状态,包括三个方法:wait()、join()、LockSupport.park()方法。
//例如调用wait()方法后等待其他线程调用notify()与notifyAll()。
WAITING,

//该状态为一个具体时间限制的等待状态。
//如以下方法:sleep(timeout)、wait(timeout)、join(timeout)、LockSupport.parkNanos、LockSupport.parkUntil
TIMED_WAITING,

//一个线程已经完成执行或者被打断状态
TERMINATED;
}
线程生命周期示意图:



二、java.lang.Thread
1. 构造函数:
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}

private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
//name必须不能为空。
if (name == null) {
throw new NullPointerException("name cannot be null");
}
// private volatile char  name[];为name的声明
this.name = name.toCharArray();
//父线程为启动线程
Thread parent = currentThread();
//打开java的安全管理器
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */

/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}

/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}

/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
//判断是否符合规则
g.checkAccess();

/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}

g.addUnstarted();

this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;

/* Set thread ID */
tid = nextThreadID();
}
2. run和start
@Override
public void run() {
//  private Runnable target;该target可以为runnable的run。适用于实现runnable接口的初始化线程的方法。
if (target != null) {
target.run();
}
}

public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();

/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);

boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}

private native void start0();


3.join()主要是等待该线程死亡。主要作用是该线程执行完成后才会运行join()后面的方法。
public final void join() throws InterruptedException {
join(0);
}

public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
//如果时间小于0,则返回异常
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (millis == 0) {
//如果时间为0,则一直等待直到当前线程死亡,即isAlive为false;每次循环等待的时间为0
while (isAlive()) {
wait(0);
}
} else {
//如果时间大于0,需要判断当前时间与join方法调用时间之间的差距,如果时间差大于参数设置的时间,则不再等待循环结束直接跳出
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
例子:1.不调用join的情况
public class TestThread {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
MyThread1 thread1 = new MyThread1(thread);
thread1.start();
}
}

class MyThread1 extends Thread {
MyThread myThread;

public MyThread1(MyThread myThread) {
this.myThread = myThread;
}

public void run() {
myThread.start();
System.out.println("end");
}
}

class MyThread extends Thread {
public void run() {
int i = 0;
while (true) {
System.out.println(this.toString() + ":" + (i++));
if(i==5){
break;
}
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出结果为:
end
Thread[Thread-0,5,main]:0
Thread[Thread-0,5,main]:1
Thread[Thread-0,5,main]:2
Thread[Thread-0,5,main]:3
Thread[Thread-0,5,main]:4
可以看到并没有相应的顺序和规律。
2.调用join()无参数的情况
修改MyThread1中的run()方法:
public void run() {
myThread.start();
try {
myThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end");
}
输出结果为:
Thread[Thread-0,5,main]:0
Thread[Thread-0,5,main]:1
Thread[Thread-0,5,main]:2
Thread[Thread-0,5,main]:3
Thread[Thread-0,5,main]:4
end
可以看到一直运行MyThread这个线程,不会运行MyThread1线程join方法下面的代码,这是由于会一直等待MyThread线程死亡,才会运行主线程的代码。
3.调用join()有参数的情况
修改MyThread1中的run()方法:
public void run() {
myThread.start();
try {
myThread.join(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("end");
}
输出结果为:
Thread[Thread-0,5,main]:0
end
Thread[Thread-0,5,main]:1
Thread[Thread-0,5,main]:2
Thread[Thread-0,5,main]:3
Thread[Thread-0,5,main]:4
可以看到在MyThread开始后,调用join(1000)后,会等待1000毫秒后,运行MyThread1的打印代码。而不是无限等待MyThread的死亡。

该方法的主要内容可以保证主线程不会优先于子线程先死亡,即如果主线程启动一个子线程,可以在子线程中调用主线程的join方法,这样就可以保证子线程死亡后主线程才会继续往下运行。

三、java.lang.runnable

runnable为接口,只有一个抽象方法run。必须实现该方法才能实现线程的调用。代码如下:
public interface Runnable {
public abstract void run();
}


四、java.util.concurrent.Callable与java.util.concurrent.FutureTask
1.该类为第三种初始化线程的方法。即实现Callable中call方法,并用FutureTask包装Callable类,通过Thread包装FutureTask之后调用start方法开启线程。call方法有返回值。调用方式如下:
public class TestCallable implements Callable<String> {

public static void main(String[] args) {
TestCallable testCallable=new TestCallable();
FutureTask futureTask=new FutureTask<String>(testCallable);
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"循环变量i的值"+i);

if(i==70){
new Thread(futureTask,"有返回的线程").start();
}
if(i==80){
try {
System.out.println("子线程返回值"+futureTask.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Override
public String call() throws Exception {
int i = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
return String.valueOf(i);
}

}
2.java.util.concurrent.Callable的代码为:可见逻辑主要是通过实现call的方法,并且有返回值
public interface Callable<V> {
V call() throws Exception;
}
3.java.util.concurrent.FutureTask
构造函数主要是包装Callable类。该类实现接口interface RunnableFuture<V> extends Runnable, Future<V>,因此可以使用Thread进行包装并调用start启动线程
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;       // ensure visibility of callable
}
实现接口的run方法。

public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
//result为callable的call()方法的返回值
V result;
boolean ran;
try {
//调用call并且将ran设置为true
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
//将结果传给futureTask的对象
if (ran)
set(result);
}
} 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);
}
}
五、Thread、runnable与callable的区别。
1.runnable与callable初始化后必须作为Thread的参数进行封装,并调用Thread的start方法进行启动线程。如下:
MyThread thread = new MyThread();
thread.start();
MyRunable runable=new MyRunable();
Thread runnableThread=new Thread(runable);
runnableThread.start();
2.runnable与callable只有一个方法,如果需要调用sleep等方法,需要调用Thread中的方法。

3.建议使用runnable与callable实现线程的class,主要是因为runnable为接口,java中不支持多继承,但支持多接口,如果继承Thread来实现线程,那么就无法再继承别的父类了。

4.runnable实现run方法;callable实现call方法,有返回值,有异常返回。

本文出自 “yinyueml之家” 博客,请务必保留此出处http://yinyueml.blog.51cto.com/4841237/1794467
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: