模板模式和回调接口介绍
模板模式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。
模板模式有2种方式:
- 子类继承父类的方式
- 结合回调接口的方式
回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。
java线程知识介绍 —— 调用start()方法不会立即执行run()方法,由cpu调度回调执行run()方法
在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
第五是死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。
1、写一个类继承自Thread类,重写run方法。用start方法启动线程
2、写一个类实现Runnable接口,实现run方法。用new Thread(Runnable target).start()方法来启动。
调用start()后,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行,只是将这个线程置于可动行状态。然后通过JVM,线程Thread会调用run()方法,执行本线程的线程体。
启动线程应该使用start()方法,而不是run()方法。如果程序从未调用线程对象的start()方法来启动它,那么这个线程对象将一直处于”新建”状态(1.新建 2.就绪 3.运行 4.阻塞 5.死亡总共5个状态),它永远也不会作为线程获得执行的机会,它只是一个普通的Java对象。当程序调用线程对象的run()方法时,与调用普通Java对象的普通方法并无任何区别,因此绝对不会启动一条新线程的。
多线程中不用start()而用run()的后果
使用run()实际为主线程,没有产生新的线程。
public class Main {
public static void main(String[] args) {
new PrintThread("Good!").run();
new PrintThread("Nice!").run();
}
}
public class PrintThread extends Thread {
private String message;
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, target, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* @param target
* the object whose {@code run} method is invoked when this thread
* is started. If {@code null}, this classes {@code run} method does
* nothing.
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public PrintThread(String message) { this.message = message; } public void run() { for (int i = 0; i < 1000; i++) { System.out.print(message); System.out.print(Thread.currentThread().getName());//添加打印当前线程,发现都是main } }
使用模板模式分析Thread和Runnable
多线程Thread类的start()方法的源码中实际上是调用了start0()方法,而这个方法是native修饰的,也就是由C++写的,在这个方法内部实际上又调用了我们Thread类的run()方法。
- 写一个类继承自Thread类,重写run方法。用start方法启动线程。这是使用了模板模式中子类继承父类的方式。
- 写一个类实现Runnable接口,实现run方法。用new Thread(Runnable target).start()方法来启动。这是使用了模板模式中基于回调接口的方式
Thread类的源码分析如下:
class Thread implements Runnable {
private Runnable target;
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the run method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* start method) and the other thread (which executes its
* run method).
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*/
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();
/**
* If this thread was constructed using a separate
* Runnable run object, then that
* Runnable object's run method is called;
* otherwise, this method does nothing and returns.
* Subclasses of Thread should override this method.
*
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
................................ //代码省略
this.target = target;
................................. 代码省略
}
}
参考:Thread的run()与start()的区别
多线程中不用start()而用run()的后果
多线程陷阱(用户应定义run方法但不要调用)
多线程Thread类start方法原理
模板模式之spring的jdbcTemplate