模板模式之Thread与Runnable

模板模式和回调接口介绍

模板模式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。

模板模式有2种方式:

  1. 子类继承父类的方式
  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()方法。

  1.  写一个类继承自Thread类,重写run方法。用start方法启动线程。这是使用了模板模式中子类继承父类的方式。
  2.   写一个类实现Runnable接口,实现run方法。用new Thread(Runnable target).start()方法来启动。这是使用了模板模式中基于回调接口的方式

  Thread类的源码分析如下:
class Thread implements Runnable {

    /* What will be run. */
    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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值