美文网首页
02给女朋友讲讲并发编程-线程的创建

02给女朋友讲讲并发编程-线程的创建

作者: XueFengDong | 来源:发表于2020-12-20 22:00 被阅读0次

    一、创建线程

    1.使用Thread类

            Thread t = new Thread(){
                //创建线程对象,重写run方法
                @Override
                public void run() {
                    //此处是该线程要执行的内容
                    log.debug("Running");
                }
            };
            t.setName("t1");
            t.start();
    

    2.使用Runnable接口

            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    log.debug("Running");
                }
            };
            Thread t = new Thread(runnable);
            t.setName("t1");
            t.start();
    

    由于Runnable接口中只有一个方法,并且含有@FunctionalInterface注解,所以Runnable接口为函数式接口,可以使用lambda表达式简化代码,如下:

            Thread t = new Thread(() -> log.debug("running"),"t1");
            t.start();
    

    Thread与Runnable之间的关系
    首先我们创建Runnable对象时,重写的是Runnable接口自身的run()方法:

    @FunctionalInterface
    public interface Runnable {
        /**
         * When an object implementing interface <code>Runnable</code> is used
         * to create a thread, starting the thread causes the object's
         * <code>run</code> method to be called in that separately executing
         * thread.
         * <p>
         * The general contract of the method <code>run</code> is that it may
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */
        public abstract void run();
    }
    

    当我们把Runnable对象传入Thread构造方法时,会调用init()方法,并将Runnable对象传入:

        /**
         * Allocates a new {@code Thread} object. This constructor has the same
         * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
         * {@code (null, target, name)}.
         *
         * @param  target
         *         the object whose {@code run} method is invoked when this thread
         *         is started. If {@code null}, this thread's run method is invoked.
         *
         * @param  name
         *         the name of the new thread
         */
        public Thread(Runnable target, String name) {
            init(null, target, name, 0);
        }
    

    进入init()方法后,我们会发现Thread重载了init()方法,继续传入Runnable对象

        /**
         * Initializes a Thread with the current AccessControlContext.
         * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)
         */
        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {
            init(g, target, name, stackSize, null, true);
        }
    

    再次进入重载后的init()方法,我们发现会将Runnable对象传给Thread类中的定义好的变量:

    /**
         * Initializes a Thread.
         *
         * @param g the Thread group
         * @param target the object whose run() method gets called
         * @param name the name of the new Thread
         * @param stackSize the desired stack size for the new thread, or
         *        zero to indicate that this parameter is to be ignored.
         * @param acc the AccessControlContext to inherit, or
         *            AccessController.getContext() if null
         * @param inheritThreadLocals if {@code true}, inherit initial values for
         *            inheritable thread-locals from the constructing thread
         */
        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();
            // 此处将我们之前传入的Runnable对象赋给Thread类中的target
            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();
        }
    

    最后我们发现,最终还是执行Thread类中的run方法,如果Runnable对象不为空,则会执行。

        /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see     #start()
         * @see     #stop()
         * @see     #Thread(ThreadGroup, Runnable, String)
         */
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
    

    3.使用FutureTask创建线程并获取执行结果

        public static void main(String[] args) throws ExecutionException, InterruptedException {
            FutureTask<String> futureTask = new FutureTask(() -> {
                log.debug("Running");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "执行成功";
            });
    
            Thread t1 = new Thread(futureTask,"t1");
            t1.start();
            //获取执行结果,等待t1线程执行完成,会使main线程进入阻塞状态。
            String result = futureTask.get();
            log.debug("{}",result);
        }
    

    二、多线程执行现象

        public static void main(String[] args) {
    
            //开启两个线程
            new Thread(() -> {
                while (true) {
                    log.debug("Running");
                }
            }, "t1").start();
    
            new Thread(() -> {
                while (true) {
                    log.debug("Running");
                }
            }, "t2").start();
    
        }
    

    输出结果:

    21:55:06.733 DEBUG [t2] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t2] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t2] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t2] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t2] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t2] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t1] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t1] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t1] com.dxf.线程执行现象.Test1 - Running
    21:55:06.733 DEBUG [t1] com.dxf.线程执行现象.Test1 - Running
    

    结论:两条线程会并行交替执行,谁先谁后不由我们控制,由底层的任务调度器来决定的。

    相关文章

      网友评论

          本文标题:02给女朋友讲讲并发编程-线程的创建

          本文链接:https://www.haomeiwen.com/subject/jmytnktx.html