1. 构造线程
这里先放上Thread.java
中 init()
的源代码
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
// 当前线程为该线程的父线程
Thread parent = currentThread();
this.group = g;
// 设置daemon与priority
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 (inheritThreadLocals && 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();
}
一个新构造的线程对象是由其parent线程来进行空间分配的,而child线程继承了parent是否为Daemon、优先级和加载资源的contextClassLoader以及可继承的
2.启动线程
调用start()
方法就可以启动这个线程
这里介绍一下三种构造线程的方法:
-
Thread类
调用
run()
和start()
的区别:public class ThreadExample { public static void main(String[] args) { Thread t1 = new ThreadEx(); t1.setName("thread A"); t1.run(); t1.start(); } } class ThreadEx extends Thread{ @Override public void run() { System.out.println("this is Thread: "+currentThread()); } } /* this is Thread: Thread[main,5,main] this is Thread: Thread[thread A,5,main] */
可以看出,直接调用
run()
方法,是使用主线程执行操作。而start()
是创建子线程。 -
使用
Runnable
接口Thread t2 = new Thread(new Runnable() { @Override public void run() { System.out.println("Thread: " + Thread.currentThread().getName()); } },"Thead B"); /* Thread: Thread B */
-
如果线程需要有返回值,则考虑用
Callable
接口class Pet{ private String pet = "pet"; int age = 10; static{ System.out.println("loading Pet class"); } @Override public String toString() { return "Pet{" + "pet='" + pet + '\'' + ", age=" + age + '}'; } }
这里使用反射的方法来创建Pet类
class TaskCall implements Callable<Pet>{ @Override public Pet call() throws Exception { Class p = Class.forName("chapter4.Pet"); // 使用这种方法,会导致静态代码块的加载 Pet pet = (Pet)p.newInstance(); Field f = p.getDeclaredField("pet"); // 由于是私有变量,所以需要进行权限 f.setAccessible(true); f.set(pet,"cat"); return pet; } } // main FutureTask<Pet> future = new FutureTask<Pet>(new TaskCall()); new Thread(future).start(); Pet pet = future.get(); System.out.println(pet.toString()); /* loading Pet class Pet{pet='cat', age=10} */
3.中断
中断可以理解为线程的一个标识位属性。中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的 interrupt()
方法对其进行中断操作。
isInterrupted()
来进行判断是否被中断,也可以调用静态方法 Thread.interrupted()
对当前线程的中断标识位进行复位。
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
private native boolean isInterrupted(boolean ClearInterrupted);
代码分析:
public class Interrupted {
public static void main(String[] args) throws Exception {
// sleepThread不停的尝试睡眠
Thread sleepThread = new Thread(new SleepRunner(), "SleepThread");
sleepThread.setDaemon(true);
// busyThread不停的运行
Thread busyThread = new Thread(new BusyRunner(), "BusyThread");
busyThread.setDaemon(true);
sleepThread.start();
busyThread.start();
// 休眠5秒,让sleepThread和busyThread充分运行
TimeUnit.SECONDS.sleep(5);
sleepThread.interrupt();
busyThread.interrupt();
System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted());
System.out.println("BusyThread interrupted is " + busyThread.isInterrupted());
// 防止sleepThread和busyThread立刻退出
SleepUtils.second(2);
}
static class SleepRunner implements Runnable {
@Override
public void run() {
while (true) {
SleepUtils.second(10);
}
}
}
static class BusyRunner implements Runnable {
@Override
public void run() {
while (true) {
}
}
}
}
/*
SleepThread interrupted is false
BusyThread interrupted is true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at chapter4.SleepUtils.second(SleepUtils.java:8)
at chapter4.Interrupted$SleepRunner.run(Interrupted.java:28)
at java.lang.Thread.run(Thread.java:748)
*/
**注意:**在 waiting 和 timed waiting状态下,使用interrupt()
,会报出异常!
4.安全地终止线程
中断操作是一种简便的线程间交互方式,而这种交互方式最适合用来取消或停止任务。除了中断以外,还可以利用一个boolean变量来控制是否需要停止任务并终止该线程。
public class shutdown {
public static void main(String[] args) throws Exception {
Runner one = new Runner();
Thread countThread = new Thread(one, "CountThread1");
countThread.start();
// 睡眠1秒,main线程对CountThread进行中断,使CountThread能够感知中断而结束
TimeUnit.SECONDS.sleep(1);
countThread.interrupt();
Runner two = new Runner();
countThread = new Thread(two, "CountThread2");
countThread.start();
// 睡眠1秒,main线程对Runner two进行取消,使CountThread能够感知on为false而结束
TimeUnit.SECONDS.sleep(1);
two.cancel();
}
private static class Runner implements Runnable {
private long i;
private volatile boolean on = true;
@Override
public void run() {
while (on && !Thread.currentThread().isInterrupted()){
i++;
}
System.out.println("Count i = " + i + " "+ Thread.currentThread());
}
public void cancel() {
on = false;
}
}
}
/*
Count i = 723186225 Thread[CountThread1,5,main]
Count i = 763222569 Thread[CountThread2,5,main]
*/
main线程通过中断操作和
cancel()
方法均可使 CountThread 得以终止。
next: 线程间通讯