编程那点事编程那点事

专注编程入门及提高
探究程序员职业规划之道!

使用内部类的方式实现多线程

这并不是一种新的实现线程的方式,只是另外的一种写法。比如有些情况我们的线程就想执行一次,以后就用不到了。那么像上面两种方式都还要再定义一个类,显得比较麻烦,我们就可以通过匿名内部类的方式来实现。使用内部类实现依然有两种,分别是继承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方法。


未经允许不得转载: 技术文章 » Java编程 » 使用内部类的方式实现多线程

专注编程入门及提高,探究程序员职业规划之道!