1 Thread
1.1 introductions
java.lang
类 Thread
java.lang.Object
java.lang.Thread
所有已实现的接口:
public class Thread
extends Object
implements Runnable
线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread
对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。
当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main
方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
1.调用了 Runtime
类的 exit
方法,并且安全管理器允许退出操作发生。
2.非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run
方法之外的异常。
创建新执行线程有两种方法。一种方法是将类声明为 Thread
的子类。该子类应重写 Thread
类的 run
方法。接下来可以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成:
class PrimeThreadextends Thread {
longminPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public voidrun() {
//compute primes larger than minPrime
. . .
}
}
然后,下列代码会创建并启动一个线程:
PrimeThreadp = new PrimeThread(143);
p.start();
创建线程的另一种方法是声明实现 Runnable
接口的类。该类然后实现 run
方法。然后可以分配该类的实例,在创建 Thread
时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:
classPrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger thanminPrime
. . .
}
}
然后,下列代码会创建并启动一个线程:
PrimeRunp = new PrimeRun(143);
new Thread(p).start();
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。
从以下版本开始:JDK1.0
另请参见:Runnable, Runtime.exit(int), run(), stop()
| currentThread |
getName | |
| getPriority |
| run |
| sleep |
| start |
toString | |
| yield |
| setDaemon |
1.2 example
1.2.1 customizedThread
public class MyThread extends Thread{
public void run() {
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}
1.2.2 test
public static void main(String[] args){
MyThread myThread1=new MyThread();
//启动线程
myThread1.setName("hah");
myThread1.start();
MyThread myThread2=new MyThread();
myThread2.setName("线程2");
myThread2.start();
//Thread的currentThread()方法可以得到当前线程的对象
Thread.currentThread().setName("Main");
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
@Test
//如果在test里面测试,会受到test线程的影响,不能饱和执行线程。
public void testMyThread(){
MyThread myThread=new MyThread();
//启动线程
myThread.setName("线程1");
myThread.start();
MyThread myThread1=new MyThread();
myThread1.setName("线程2");
myThread1.start();
}
2 Runnable
2.1 introduction
java.lang
接口 Runnable
所有已知子接口:
RunnableFuture<V>,RunnableScheduledFuture<V>
所有已知实现类:
AsyncBoxView.ChildState, FutureTask, RenderableImageProducer, SwingWorker, Thread, TimerTask
public interface Runnable
Runnable
接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run
的无参数方法。
设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread
类实现了 Runnable
。激活的意思是说某个线程已启动并且尚未停止。
此外,Runnable
为非 Thread
子类的类提供了一种激活方式。通过实例化某个 Thread
实例并将自身作为运行目标,就可以运行实现 Runnable
的类而无需创建 Thread
的子类。大多数情况下,如果只想重写 run()
方法,而不重写其他 Thread
方法,那么应使用 Runnable
接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。
从以下版本开始: JDK1.0
2.2 使用Runnable接口实现类的底层原理
(1).Thread类实现自Runnable接口,且包含属性Runnable target。
Publicclass Thread implements Runnable {
private int priority;
private Thread threadQ;
private long eetop;
....
private Runnable target;
}
(2).Runnable接口只有一个抽象方法
| run |
(3).Thread类本身的run方法源码,也是执行了自身Runnable属性的run方法。而采用继承Thread类创建线程子类的方式,是重写了这个run方法。重点代码见标红。
public void run() {
if (target != null) {
target.run();
}
}
(4).Thread的传Runnable实例的构造方法源码。利用多态的特征,将实现了Runnable接口的类赋值给Thread自身的Runnable属性,从而调用的run方法就是实现类的run方法。
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize,AccessControlContext acc) {
if (name == null) {
throw newNullPointerException("name cannot be null");
}
this.name = name.toCharArray();
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess();
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);
this.stackSize = stackSize;
tid = nextThreadID();
}
2.3 example
2.3.1 Runnable实现类
public class MyRunnable implements Runnable{
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
2.3.2 test
public static void main(String[] args){
//创建任务对象
MyRunnable myrun=new MyRunnable();
//通过Thread类的构造方法分配新的Thread对象
Thread t1=new Thread(myrun,"run1");
Thread t2=new Thread(myrun,"run2");
Thread t3=new Thread(myrun,"run3");
t1.start();
t2.start();
t3.start();
}
3 Thread类的启动原理
run:用来封装线程任务的,无法启动线程
start:先启动线程,再调用run方法。
Threadl类的start方法源码,主要是调用了start0方法。而start0方法是native修饰的,也就是调用了一个非java代码的接口。由于启动线程涉及到jvm,所以这里的启动过程可能有c或者其他语言来实现的。重点代码标红。与这个问题相关的知识是,jvm是用c和汇编等语言开发的。在底层的要看start0方法所关联的c代码等了。
public synchronized void start() {
if (threadStatus != 0)
throw newIllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();
4 Thread常用的方法
| setPriority |
同样的,在底层源码中,setPriority方法中调用了native的setPriority0的方法。
| sleep |
Sleep属于静态方法,需要用类调用。
public void run() {
for(int i=0;i<100;i++){
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"--"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
| join |
| yield |
Yield属于静态方法,需要用类调用。
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"--"+i);
Thread.yield();
}
}
| setDaemon |
setDaemon方法必须在启动线程前调用。
public static void main(String[] args){
//创建任务对象
MyRunnable myrun=new MyRunnable();
SleepTask st=new SleepTask();
YieldTask yt=new YieldTask();
//通过Thread类的构造方法分配新的Thread对象
Thread t1=new Thread(myrun,"run1");
Thread t2=new Thread(myrun,"run2");
Thread t3=new Thread(myrun,"run3");
Thread t4=new Thread(st,"runsleep");
Thread t5=new Thread(yt,"runyield");
t1.start();
//t1.start();
try {
t1.join(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
t3.start();
t5.setDaemon(true);
t5.start();
//t4.start();
ThreadGroup tg=t2.getThreadGroup();
System.out.println(tg);
Thread.State ts=t2.getState();
System.out.println(ts);
//设置线程的优先级
t1.setPriority(1);
t2.setPriority(10);
}