一、线程的基本概念
二、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 {
//main()
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
MyThread thread1 = new MyThread();
thread.start();
thread1.start();
}
}
class MyThread extends Thread {
public void run() {
int i = 0;
while (true) {
System.out.println(this.toString() + ":" + (i++));
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}输出结果为:
Thread[Thread-1,5,main]:0 Thread[Thread-0,5,main]:0 Thread[Thread-0,5,main]:1 Thread[Thread-1,5,main]:1 Thread[Thread-1,5,main]:2 Thread[Thread-0,5,main]:2 Thread[Thread-1,5,main]:3 Thread[Thread-0,5,main]:3
可以看到并没有相应的顺序和规律。
2.调用join()无参数的情况
修改main()方法为:
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
MyThread thread1 = new MyThread();
thread.start();
thread.join();
thread1.start();
thread1.join();
}输出结果为:
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 Thread[Thread-0,5,main]:5 Thread[Thread-0,5,main]:6 Thread[Thread-0,5,main]:7
可以看到一直运行Thread-0这个线程,不会运行另一个线程,这是由于会一直等待Thread-0线程死亡,但由于是死循环,因此不会结束。
3.调用join()有参数的情况
修改mian()方法为:
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
MyThread thread1 = new MyThread();
thread.start();
Long tt1=System.currentTimeMillis();
thread.join(100);
Long ee1=System.currentTimeMillis();
System.out.println(ee1-tt1);
thread1.start();
Long tt2=System.currentTimeMillis();
thread1.join(100);
Long ee2=System.currentTimeMillis();
System.out.println(ee2-tt2);
}输出结果为:
Thread[Thread-0,5,main]:0 100 Thread[Thread-1,5,main]:0 100 Thread[Thread-0,5,main]:1 Thread[Thread-1,5,main]:1 Thread[Thread-0,5,main]:2 Thread[Thread-1,5,main]:2
可以看到在Thread-0开始后,调用join(100)后,会等待100毫秒后,运行Thread-1的run方法。而不是无限等待Thread-1的死亡。
该方法的主要内容可以保证主线程不会优先于子线程先死亡,即如果主线程启动一个子线程,可以在子线程中调用主线程的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
JDK源码学习(7)-Thread、Runnable与Callable
原文:http://yinyueml.blog.51cto.com/4841237/1794467