这并不是一种新的实现线程的方式,只是另外的一种写法。比如有些情况我们的线程就想执行一次,以后就用不到了。那么像上面两种方式都还要再定义一个类,显得比较麻烦,我们就可以通过匿名内部类的方式来实现。使用内部类实现依然有两种,分别是继承Thread类和实现Runnable接口。代码如下:package com.hy.thread.t3;
public class DemoThread {
public static void main(String[] args) {
// 基于子类的实现
new Thread() {
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
try {
Thread.sleep(1000); // 休息1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
// 基于接口的实现
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
try {
Thread.sleep(1000); // 休息1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
// 主线程的方法
while (true) {
System.out.println(Thread.currentThread().getName() + " is running ... "); // 打印当前线程的名字
try {
Thread.sleep(1000); // 休息1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
可以想象一下,我能不能既基于接口,又基于子类呢?像下面的代码会执行出什么样子呢?package com.hy.thread.t3;
public class DemoThred2 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("runnable is running ... "); // 打印当前线程的名字
try {
Thread.sleep(1000); // 休息1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}) {
public void run() {
while (true) {
System.out.println("sub is running ... "); // 打印当前线程的名字
try {
Thread.sleep(1000); // 休息1000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
运行结果如下:sub is running ...
sub is running ...
sub is running ...
我们可以看到,其实是基于子类的执行了,为什么呢,其实很简单,我们先来看一下为什么不基于子类的时候Runnable的run方法可以执行。这个要从Thread的源码看起,下面是我截取的代码片段。public Thread(Runnable target)
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
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();
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 (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();
}
其实上面的众多代码就是为了表现 this.target = target 那么target是什么呢,是Thread类的成员变量。那么在什么地方用到了target呢?下面是run方法的内容。@Override
public void run() {
if (target != null) {
target.run();
}
}
我们可以看到,如果通过上面的构造方法传入target,那么就会执行target中的run方法。可能有朋友就会问了,我们同时继承Thread类和实现Runnable接口,target不为空,那么为何不执行target的run呢。不要忘记了,我们在子类中已经重写了Thread类的run方法,因此run方法已经不在是我们看到的这样了。那当然也就不回执行target的run方法。