精华内容
下载资源
问答
  • Runnable

    千次阅读 2020-04-20 10:58:26
    package chapter1; public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { Thread thread = Thread.currentThread(); ...
    package chapter1;
    
    public class MyRunnable implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                Thread thread = Thread.currentThread();
                System.out.println(thread.getName()+": "+i);
            }
        }
    }
    
    
    package chapter1;
    
    public class Demo {
        public static void main(String[] args) {
            MyRunnable myRunnable = new MyRunnable();
    //        myRunnable.run();
    //        Thread thread = Thread.currentThread();
    //        System.out.println(thread);
            Thread t1 = new Thread(myRunnable,"线程1");
            Thread t2 = new Thread(myRunnable,"线程2");
            t1.start();
            t2.start();
        }
    }
    
    
    展开全文
  • 彻底理解Runnable和Thread的区别

    万次阅读 多人点赞 2019-07-30 09:45:42
      在实际工作中,我们很可能习惯性地选择Runnable或Thread之一直接使用,根本没在意二者的区别,但在面试中很多自以为是的菜货面试官会经常而且非常严肃的问出:请你解释下Runnable或Thread的区别?尤其是新手就...

    鄙人的新书《Elasticsearch权威指南》正式出版发行,欢迎购买!本书由华为、中兴高级技术专家全面审读并撰序,助您挑战百万年薪 购书链接:在这里插入图片描述

    《Elasticsearch权威指南》

    欢迎关注鄙人公众号,技术干货随时看!
    在这里插入图片描述

      在实际工作中,我们很可能习惯性地选择Runnable或Thread之一直接使用,根本没在意二者的区别,但在面试中很多自以为是的菜货面试官会经常而且非常严肃的问出:请你解释下Runnable或Thread的区别?尤其是新手就容易上当,不知如何回答,就胡乱编一通。鄙人今天告诉你们这二者本身就没有本质区别,就是接口和类的区别。问出这个问题的面试官本身就是个二流子!如果非要说区别,请看如下:

    1. Runnable的实现方式是实现其接口即可
    2. Thread的实现方式是继承其类
    3. Runnable接口支持多继承,但基本上用不到
    4. Thread实现了Runnable接口并进行了扩展,而Thread和Runnable的实质是实现的关系,不是同类东西,所以Runnable或Thread本身没有可比性。

      网络上流传的最大的一个错误结论:Runnable更容易可以实现多个线程间的资源共享,而Thread不可以! 这是一个二笔的结论!网络得出此结论的例子如下:

    //program--Thread
    public class Test {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            new MyThread().start();
            new MyThread().start();
    
        }
    
    
         static class MyThread extends Thread{
            private int ticket = 5;
            public void run(){
                while(true){
                    System.out.println("Thread ticket = " + ticket--);
                    if(ticket < 0){
                        break;
                    }
                }
            }
        }
    }
    

    运行结果如下:

    Thread ticket = 5
    Thread ticket = 5
    Thread ticket = 4
    Thread ticket = 3
    Thread ticket = 2
    Thread ticket = 1
    Thread ticket = 0
    Thread ticket = 4
    Thread ticket = 3
    Thread ticket = 2
    Thread ticket = 1
    Thread ticket = 0
    
    Process finished with exit code 0
    
    

      很显然,总共5张票但卖了10张。这就像两个售票员再卖同一张票,原因稍后分析。现在看看使用runnable的结果:

    //program--Runnable
    public class Test2 {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            MyThread2 mt=new MyThread2();
            new Thread(mt).start();
            new Thread(mt).start();
    
    
        }
        static class MyThread2 implements Runnable{
            private int ticket = 5;
            public void run(){
                while(true){
                    System.out.println("Runnable ticket = " + ticket--);
                    if(ticket < 0){
                        break;
                    }
                }
            }
        }
    }
    

      运行结果如下:

    
    Runnable ticket = 5
    Runnable ticket = 4
    Runnable ticket = 3
    Runnable ticket = 1
    Runnable ticket = 0
    Runnable ticket = 2
    
    Process finished with exit code 0
    
    

      嗯,嗯,大多数人都会认为结果正确了,而且会非常郑重的得出:Runnable更容易可以实现多个线程间的资源共享,而Thread不可以! 真的是这样吗?大错特错!
      program–Thread这个例子结果多卖一倍票的原因根本不是因为Runnable和Thread的区别,看其中的如下两行代码:

            new MyThread().start();
            new MyThread().start();
    

      例子中,创建了两个MyThread对象,每个对象都有自己的ticket成员变量,当然会多卖1倍。如果把ticket定义为static类型,就离正确结果有近了一步(因为是多线程同时访问一个变量会有同步问题,加上锁才是最终正确的代码)。
    现在看program–Runnable例子中,如下代码:

            MyThread2 mt=new MyThread2();
            new Thread(mt).start();
            new Thread(mt).start();        
    

      只创建了一个Runnable对象,肯定只卖一倍票(但也会有多线程同步问题,同样需要加锁),根本不是Runnable和Thread的区别造成的。再来看一个使用Thread方式的正确例子:

    public class Test3  extends Thread {
    
            private int ticket = 10;
    
            public void run(){
                for(int i =0;i<10;i++){
                    synchronized (this){
                        if(this.ticket>0){
                            try {
                                Thread.sleep(100);
                                System.out.println(Thread.currentThread().getName()+"卖票---->"+(this.ticket--));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
    
            public static void main(String[] arg){
                Test3 t1 = new Test3();
                new Thread(t1,"线程1").start();
                new Thread(t1,"线程2").start();
            }
    
    }
    

    运行结果如下:

    线程1卖票---->10
    线程1卖票---->9
    线程1卖票---->8
    线程1卖票---->7
    线程1卖票---->6
    线程1卖票---->5
    线程1卖票---->4
    线程1卖票---->3
    线程1卖票---->2
    线程1卖票---->1
    
    Process finished with exit code 0
    
    

      上例中只创建了一个Thread对象(子类Test3),效果和Runnable一样。synchronized这个关键字是必须的,否则会出现同步问题,篇幅太长本文不做讨论。
      上面讨论下来,Thread和Runnable没有根本的没区别,只是写法不同罢了,事实是Thread和Runnable没有本质的区别,这才是正确的结论,和自以为是的大神所说的Runnable更容易实现资源共享,没有半点关系!
      现在看下Thread源码:

    public
    class Thread implements Runnable {
        /* Make sure registerNatives is the first thing <clinit> does. */
        private static native void registerNatives();
        static {
            registerNatives();
        }
    
        private volatile String name;
        private int            priority;
        private Thread         threadQ;
        private long           eetop;
    

      可以看出,Thread实现了Runnable接口,提供了更多的可用方法和成员而已。

      结论,Thread和Runnable的实质是继承关系,没有可比性。无论使用Runnable还是Thread,都会new Thread,然后执行run方法。用法上,如果有复杂的线程操作需求,那就选择继承Thread,如果只是简单的执行一个任务,那就实现runnable。
      再遇到二笔面试官问Thread和Runnable的区别,你可以直接鄙视了!

    展开全文
  • 你不知道的Runnable接口,深度解析Runnable接口

    万次阅读 多人点赞 2016-11-04 14:12:47
    本文描述的是Android中的Runnable接口。因Android中的线程源自于Java,所以首先需要了解Java中的线程,有关Java中的线程请看这篇文章Android(线程一) 线程 ! Java开发中,我们实现多线程,有两种方式,一种是继承...

        本文描述的是Android中的Runnable接口 。因Android中的线程源自于Java,所以首先需要了解Java中的线程,有关Java中的线程请看这篇文章Android(线程一) 线程  !

        Java开发中,我们实现多线程,有两种方式, 一种是继承Thread类,一种是实现Runnable接口。但是,我们真的理解Runnable?Runnable和Thread一样吗?都是开启新的线程吗? 为何明明在子线程使用Handler的post(Runnable),最终还是在主线程中执行呢?...带着这些疑问,我们来开始今天的博文。本文的例子是基于Android Studio。

    一、首先通过例子实现这两种方式。

    1、继承Thread类。

          Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了。

    首先新建一个MyThread类继承自Thread类,重写run()方法,在控制输入传递的文本,

     

    public class MyThread extends Thread {
    
        private String name;
    
        public MyThread(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
            System.out.println("MyThread is " + name);
        }
    }

    接着创建该类,启动该线程(Thread类的start()方法),并输出线程的id,

     

     

    public class Test1 {
    
        public static void main(String[] args){
            MyThread myThread1=new MyThread("线程1");
            MyThread myThread2=new MyThread("线程2");
            MyThread myThread3=new MyThread("线程3");
    
            myThread1.start();
            myThread2.start();
            myThread3.start();
    
            System.out.println("myThread1 id ="+myThread1.getId());
            System.out.println("myThread1 id ="+myThread2.getId());
            System.out.println("myThread1 id ="+myThread3.getId());
    
    
        }
    
    }

     

    控制台输出截图如下,

    开启了三个线程。

    PS:如果你也是使用Android Studio,控制台中文输出可能是乱码,那么可以参考这篇文章去解决,Android Studio中Java控制台中文输出乱码

    2、实现Runnable接口。

          Runnable只是一个接口,它里面只有一个run()方法,没有start()方法,

     

        public interface Runnable{  
        public void run();  
        } 

          所以,即使实现了Runnable接口,那也无法启动线程,必须依托其他类。

     

          而Thread类,有一个构造方法,参数是Runnable对象,也就是说可以通过Thread类来启动Runnable实现多线程。

     

       public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }

          所以,实现Runnable接口后,需要使用Thread类来启动。
    下面还是上案例说明,

     

    创建一个类MyRunnable,实现Runnable接口,

     

    public class MyRunnable implements Runnable {
    
        private String name;
    
        public MyRunnable(String name) {
            this.name = name;
        }
        @Override
        public void run() {
            System.out.println("MyRunnable is " + name);
        }
    }

    和继承Thread类的实现方法基本一样,其实Thread类也是实现了Runnable接口,

     

    下面是调用以及启动线程并打印线程的id,启动线程还是调用Thread类的start()方法,

     

    public class Test1 {
    
        public static void main(String[] args){
    
            MyRunnable myRunnable1=new MyRunnable("Runnable1");
            MyRunnable myRunnable2=new MyRunnable("Runnable2");
            MyRunnable myRunnable3=new MyRunnable("Runnable3");
    
            Thread myThread1=new Thread(myRunnable1);
            myThread1.start();
            System.out.println("myThread1 id ="+myThread1.getId());
            Thread myThread2=new Thread(myRunnable2);
            myThread2.start();
            System.out.println("myThread1 id ="+myThread2.getId());
            Thread myThread3=new Thread(myRunnable3);
            myThread3.start();
            System.out.println("myThread1 id ="+myThread3.getId());
        }
    
    }
    

     

    控制台输出截图如下,

    可以看到,启动了三个不同的线程。

    小结:通过上面的两个小例子程序,我们可以得知,只是实现Runnable接口,并不能启动或者说实现一个线程。Runnable接口,并不能代表一个线程。Runnable接口和线程是两个不同的概念!

    换句话说,一个类,实现Runnable接口,这个类可以做很多事情,不仅仅只被用于线程,也可以用于其他功能!

    二、 为何明显使用Handler的post(Runnable),最终还是在主线程中执行呢?

    1.我们都知道使用Handler更新UI,有时候会调用 Handler.post()方法更新UI, Handler.post()方法的源码如下,

     

       public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);
        }

     

    getPostMessage()方法是创建一个Message对象,并且将参数的Runnable对象赋值给了该Message对象的callback属性,

     

        private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }

    sendMessageDelayed()方法内部会继续调用其他方法(此处不再详说),而这一系列的方法最终的功能是,将创建的Message对象加入到消息队列中。详情请看 Android 源码解析Handler处理机制(二)

     

    2.执行Looper.loop()方法,该方法将会从消息循环中循环取出消息,取出消息后,会执行下面的代码,

     

      public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }

    参数是消息队列取出的消息,如果该消息的callback属性(Runnable对象)等于‘null’,则会执行handleMessage()方法,否则,将执行handleCallback()方法,我们重点看看handleCallback()方法,有关handleMessage()详情请看 Android 源码解析Handler处理机制(二)

     

     

       private static void handleCallback(Message message) {
            message.callback.run();
        }

    通过上面的分析,这一块是不是更加清晰、明白了!

    message.callback.run();

    很显然该方法仅仅是执行了消息的callback属性(Runnable对象)的run()方法,并没有开启子线程,它其实还是运行在Handler所在的线程即主线程中。

     

    小结:使用Handler.post()方法更新UI,只是将消息加入到消息队列,并且设置消息的callback属性为参数Runnable对象的值;从消息循环中取出消息时,将执行消息对象的callback属性(Runnable对象)run()方法,还是在Handler所在的主线程中运行的,并没有开启新的子线程。

    总结:读过本篇文章后,相信读者对Handler.post()方法更新UI理解会更清晰、完整、透彻,并且对Runnable接口会有新的不一样的认识。

     

    PS:在使用Runnable时,可能会内存泄露。Runnable是一个匿名内部类,因此它对当前Activity有一个隐式引用。如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。那么该怎么解决这种问题呢?代码如下,

     

        static class MyRunnable implements Runnable {
            @Override
            public void run() {
           //执行任务
            }
        }

    使用 静态内部类,避免了Activity的内存资源泄漏。

     

     

    推荐文章: Android 更新UI的几种方法

                     Android 源码解析Handler处理机制(一)

                    Android 源码解析Handler处理机制(二)

    欢迎大家关注我的公众号

     

     

     

    展开全文
  • Runnable

    2021-01-04 14:59:51
    创建一个Runnable接口的实现类 package ThreadDemo01;/* @Author wanghongyuan @Date 2021/1/4 */ // 1.创建一个Runnable接口的实现类 public class RunnableImpl implements Runnable{ // 2.在实现类中重写...

    @java
    @线程
    Runnnable的用法

    创建一个Runnable接口的实现类

    package ThreadDemo01;/*
     @Author wanghongyuan
      @Date 2021/1/4 
     
    */
    //      1.创建一个Runnable接口的实现类
    
    public class RunnableImpl implements Runnable{
        //      2.在实现类中重写Runnable接口的run方法,设置线程任务
    
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+"-->" + i);
            }
        }
    }
    
    

    在main方法中创建一个Runnable实现类对象

    package ThreadDemo01;/*
     @Author wanghongyuan
      @Date 2021/1/4 
     
    */
    /*
        创建多线程程序的第二种方式:实现Runnable接口
        java.lang.Runnable,Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现,类必须定义一个称为run的无参方法。
        java.lang.Thread类的构造方法
            Thread(Runnable target)分配新的Thread对象。
            Thread(Runnable target,String name)分配新的Thread对象
    
        实现步骤:
            1.创建一个Runnable接口的实现类
            2.在实现类中重写Runnable接口的run方法,设置线程任务
            3.创建一个Runnable接口的实现类对象
            4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象。
            5.调用Thread类中的start方法,开启新的线程执行run方法
    	
    	实现Runnable接口创建多线程程序的好处:
    		1.避免了单继承的局限性
    			一个类只能继承一个类(一个人只能一个亲爹),类继承了Thread类就不能继承其他的类
    			实现了Runnable接口,还可以继承其他的类,实现其他的接口
    		2.增强了程序的扩展性,降低了程序的耦合性(解耦)
    			实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
    			实现类中,重写了run方法:用来设置线程任务
    			创建Thread类对象,调用start方法:用来开启新的线程
    
     */
    public class RunnableDemo {
        public static void main(String[] args) {
            // 3.创建一个Runnable接口的实现类对象
            RunnableImpl impl = new RunnableImpl();
            //  4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象。
            Thread t = new Thread(impl);
            // 5.调用Thread类中的start方法,开启新的线程执行run方法
            t.start();
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+"-->" + i);
            }
    
        }
    }
    
    
    展开全文
  • extends Thread 与 implements Runnable 的区别

    万次阅读 多人点赞 2012-05-01 20:26:54
    1、通过实现Runnable接口创建线程 (1).定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。 (2).创建Runnable接口实现类的对象。 (3).创建一个Thread类的对象,...
  • Runnable接口

    2019-05-07 15:42:12
    到目前为止,线程都是通过客栈Thread类来创建的,如果需要继承其他类,而且还要使当前类实现多线程,那么可以通过Runnable接口实现。例如,一个扩展JFrame类的GUI程序不可能再继承Thread类,因为Java语言中不支持多...
  • 线程Runnable

    2019-01-07 20:22:50
    Runnable接口中只有一个run()函数,并没有start()函数,所以它必须依托其他类来使用,比如Thread类 Thread中有个以Runnable为参数的构造函数   @FunctionalInterface public interface Runnable { /** * When...
  • Runnable 线程

    2019-05-01 14:49:28
    * 1、创建:实现Runnable+重写run * 2、启动: 创建实现类对象 +Thread对象+ start * * 推荐: 避免单继承的局限性,优先使用接口 * 方便共享资源 * @author 裴新 QQ:3401997271 * */ public class StartRun ...
  • Runnable任务

    2019-05-08 22:22:35
    任务 Runnable 定义了一个可以独立运行的代码片段,通常用于界面控件的延迟处理,比如为了避免同时占用某种资源造成冲突,有时则是为了反复间隔刷新界面从而产生动画效果。 运行 个任务也有多种形式,既能在 线程中...
  • java runnable

    2020-07-12 17:58:34
    对于多线程的实现方式主要有两种:实现Runnable接口,继承Thread类对于这两种多线程的实现方式也是有着差异的。下面我们来看看怎么通过两种实现方式启动多线程。 Thread: public class MyThread extends Thread { @...
  • //仅作为学习笔记/*需求: 实现一个售票程序创建线程的第二种方式:实现Runnable接口步骤:1,定义类实现Runnable接口2,覆盖Runnable接口中的run方法将线程要运行的代码存放在该run方法中3,通过Thread 类建立线程...
  • Runnable 接口

    千次阅读 2018-05-03 19:43:12
    在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:•避免点继承的局限,一个类可以继承多个接口。•适合于资源的共享以卖票程序为例,通过Thread类完成:...
  • Runnable的使用

    2020-10-04 12:33:30
    Runnable 定义MyRunnable类实现Runnable接口。 实现run()方法,编写线程执行体。 创建线程对象,调用start()方法启动线程。 提示:推荐使用Runnable对象,因为Java单继承的局限性 参考代码 //创建线程方式二...
  • 实现Runnable接口来创建线程: 创建线程的流程如下: Runnable接口实现线程的创建代码演示: 展示结果如下: 继承thread类,实现Runnable接口,java是单继承,推荐使用Runnable接口 创建第一种和第二种方法的...
  • Thread与Runnable

    2019-10-01 02:11:41
    Thread与Runnable 概要 1.Thread与Runnable的简单介绍 2.Thread与Runnable的区别 3.Thread与Runnable举例 Thread与Runnable的简介 Runnable就是一个接口,实现接口就需...
  • 我有一个带有主标签页活动的Android应用程序,并且在单个标签页内有多个活动。...但是,我需要这些Runnable仅在主选项卡活动的Runnable完成创建列表时才运行,否则我将得到一个空列表。我正在尝试找到一种...
  • 本文为大家分享了Java多线程实现Runnable方式的具体方法,供大家参考,具体内容如下(一)步骤1.定义实现Runnable接口2.覆盖Runnable接口中的run方法,将线程要运行的代码存放在run方法中。3.通过Thread类建立线程对象...
  • Runnable与Callable

    2020-10-18 15:41:12
    Runnable与Callable 接口定义 //Callable接口 public interface Callable<V> { V call() throws Exception; } //Runnable接口 public interface Runnable { public abstract void run(); } Callable的使用...
  • 各位小伙伴们大家好,这次小编要介绍的是Runnable表达式当我们要启动一个线程去完成任务的时候,通常的做法会通过java.lang.Runnable接口来定义任务内容,并使用java.lang.Thread类来启动线程,代码如下:/*创建...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,085
精华内容 23,234
关键字:

runnable