精华内容
下载资源
问答
  • 主要介绍了java 多线程Thread与runnable区别的相关资料,java线程有两种方法继承thread类实现runnable接口,下面就提供实例帮助大家理解,需要的朋友可以参考下
  • 首先,多线程的实现方式两种:一种是继承Thread类,另一种是实现Runnable接口。 那么这两种方法的区别何在?该如何选择? 第一:他们之间的关系 查看J2EE的API看到 Thread类中: public class Thread extends ...

    首先,多线程的实现方式两种:一种是继承Thread类,另一种是实现Runnable接口。


    那么这两种方法的区别何在?该如何选择?


    第一:他们之间的关系

    查看J2EE的API看到

    Thread类中:  public class Thread extends Object implements Runnable

    Runnable接口:public interfaceRunnable

    明显可知两者:Thread类是Runnable接口的一个实现类,那么Runnable接口是何用?


    文档解释:

    Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。

    设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread 类实现了 Runnable。激活的意思是说某个线程已启动并且尚未停止。

    也就是说Runnable提供的是一种线程运行规范,具体运行线程需要通过它的实现类


    第二:通过源码分析

    我们以public class Thread1 extends Thread 这个自定义线程来追本溯源:首先查看Thread类

    其中定义了一个private Runnable target;  定义了Runnable类型的属性target,查看哪里有引用

    几个方法:

     private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {。。。}
    
    
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
       }
    
    public Thread(Runnable target) {
    	init(null, target, "Thread-" + nextThreadNum(), 0);
        }

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

    public Thread(String name) {
    	init(null, null, name, 0);
        }

     public Thread(ThreadGroup group, String name) {
    	init(group, null, name, 0);
        }

    public Thread(Runnable target, String name) {
    	init(null, target, name, 0);
        }

    public Thread(ThreadGroup group, Runnable target, String name) {
    	init(group, target, name, 0);
        }

     public Thread(ThreadGroup group, Runnable target, String name,
                      long stackSize) {
    	init(group, target, name, stackSize);
        }

    以上列出了Thread的一个初始化方法init()和所有的构造方法:可以知道,构造方法需要调用init()方法初始化线程对象,有一个Runnable类型的target对象也参与初始化。

    我们所知道的Thread类进行运行线程时是调用start()方法,我们也来查看这个方法:

    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();
            group.add(this);
            start0();
            if (stopBeforeStart) {
    	    stop0(throwableFromStop);
    	}
        }

    可知:当调用这个start()方法时,使该线程开始执行;Java 虚拟机调用该线程的 run 方法。结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。 这个方法仅作了线程状态的判断(保证一个线程不多次启动,多次启动在JVM看来这是非法的),然后把该线程添加到线程组(不多做解释)等待运行。

    那么继续看run()方法:

    public void run() {
    	if (target != null) {
    	    target.run();
    	}
        }
    可知,当Runnable实现类对象没有内容为null,则方法什么都不执行,如果有实现类对象,就调用它实现类对象实现的run()方法。这让我们想到了一个经典的设计模式:代理模式

    到此我们知道:线程的运行是依靠Thread类中的start()方法执行,并且由虚拟机调用run()方法,所以我们必须实现run()方法


    那么还是要看一下Runnable接口的设计:

    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();
    }

    可知它只有一个抽象的run()方法,完全是实实在在的线程运行规范

    第三:通过他们之间的设计模式:代理模式  再次深入

    代理模式如图:

    可知,Thread也是Runnable接口的子类,但其没有完全实现run()方法,所以说如果继承Thread类实现多线程,仍旧需要覆写run()方法。


    看两种实现多线程的基本方式


    继承Thread:

    class MyThread extends Thread{
    	private int ticket = 5;
    	public void run(){
    		for(int i = 0;i<100;i++){
    			if(ticket>0){//判断是否还有剩余票
    				System.out.println("卖票,ticket = "+ticket--);
    			}
    		}
    	}
    };
    public class ThreadDemo04{
    	public static void main(String args[]){
    		MyThread mt1 = new MyThread();
    		MyThread mt2 = new MyThread();
    		MyThread mt3 = new MyThread();
    		mt1.start();//调用线程主体让其运行
    		mt2.start();//三个地方同时卖票
    		mt3.start();
    	}
    };	

    实现Runnable:

    class MyThread implements Runnable{
    	private int ticket=5;
    	public void run(){
    		for(int i = 0;i<100;i++){
    			if(ticket>0){
    				System.out.println("卖票,ticket = "+ticket--);
    			}
    		}
    	}
    };
    public class RunnableDemo02{
    	public static void main(String args[]){
    		MyThread my1 = new MyThread();
    		new Thread(my1).start(); //启动三个线程
    		new Thread(my1).start(); //共享my1中资源
    		new Thread(my1).start(); 
    	}
    };

    可知最后:无论哪种方法都需要实现run()方法,run方法是线程的运行主体。并且,线程的运行都是调用Thread的start()方法。

    那么代理模式中Thread类就充当了代理类,它在线程运行主体运行前作了一些操作然后才运行线程的run()。首先说一下代理模式的基本特征就是对【代理目标进行增强】代理模式就不在这里详述。总之,Thread提供了很多有关线程运行前、后的操作,然后通过它的start()方法让JVM自动调用目标的run()方法


    第四:继承Thread与实现Runnable接口方法区别

    首先看一段代码:

    new Thread(
        new Runnable(){
    
                  public void run() {
                while(true){
                    try {
                            Thread.sleep(500);
                    } catch (InterruptedException e) {e.printStackTrace(); }
                        System.out.println("runnable :" + Thread.currentThread().getName());
                }                            
            }
        }
    ){
    
            public void run() {
            while(true){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {e.printStackTrace();}
    
                           System.out.println("thread :" + Thread.currentThread().getName());
            }    
        }
    
    }.start();
    

    可以预测一下这段代码是执行哪一个run()方法?

    根据以前java中基础知识可知:执行start()方法后,JVM去找run()方法,然后它找到了自己的run()方法,那么就直接运行自己的run()方法。如果找不到自己的方法它才会去找被代理的run()方法。所以它应该执行的是"thread:。。。"代码部分。可以把它放到一个main方法中,通过测试验证推断正确:


    想说明的是一个面向对象的思想:即如果没有上方第二个run()块,那么它执行的就是匿名Runnable实现类的run()方法。这说明什么,说明,Thread相当于一个执行者,而执行的代码块在Runnable实现类中定义好。这样实现执行与源码的分离,体现了面向对象的思想。这也是他们之间的一个比较大的区别。

    其他区别:

    实现Runnable接口可以实现资源共享,Thread无法完成资源共享 ----- 讨论第三点的两段代码中:继承Thread的:结果卖出了15张,各有各的票数。实现Runnable接口的方法:卖出5张,共享了资源

    实现Runnable接口比继承Thread类来实现多线程有如下明显优点:

    适合多个相同程序代码使用共同资源;

    避免由单继承局限带来的影响;

    增强程序的健壮性,代码能够被多个线程共享,代码数据是独立的;


    使用的选择

    通过比对区别可知:

    由于面向对象的思想,以及资源共享,代码健壮性等,一般都是使用实现Runnable接口来实现多线程,也比较推荐


    以上为多线程的一点个人总结,后期继续跟上。若有表述不当之处,感谢您的私信指出,我将尽快解决



    展开全文
  • 细说多线程Thread与Runnable Runnable 方式可以避免Thread方式由于Java单继承性带来的缺陷 Runnable的代码可以被多个线程共享,(同一runnable),适合于多个线程处理同一资源的情况 线程的生命周期 ...
    细说多线程之Thread与Runnable
    

    Runnable 方式可以避免Thread方式由于Java单继承性带来的缺陷

    Runnable的代码可以被多个线程共享,(同一runnable),适合于多个线程处理同一资源的情况

    线程的生命周期

    创建 就绪 阻塞 运行 终止

    创建:new 了这个对象

    就绪:start 创建了线程对象后,调用了start方法,注意此时线程只是进入了线程队列,等待CPU服务,具备了运行条件,但不一定已经开始运行了

    运行:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run方法中的逻辑

    终止:线程的run方法执行完毕,或者调用了stop方法,线程便进入终止状态

    阻塞:一个正在执行的线程在某些情况下,由于某种原因让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了
    sleep方法;

    阻塞状态位于就绪和运行状态之间

    用户线程 main线程 守护线程 子线程 daemon标记的是守护线程

    线程的概念 主线程 用户线程 子线程 守护线程 线程的生命周期状态 以及如何获取资源被CPU执行

    考虑到代码的可扩展性,建议多使用runnable这种方式创建线程

    展开全文
  • 多线程Thread与Runnable 以及五种状态

    千次阅读 2017-06-05 19:24:04
    多线程Thread与Runnable 以及五种状态 1、新建状态(New):新创建了一个线程对象。private static void showThread() { //建立线程对象 MyThread myThread = new MyThread(); //开启线程 myThread.start(); }...

    多线程Thread与Runnable 以及五种状态

    在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限。
    这样程序可以正常完成交互式运行。那么为啥非要使用start();方法启动多线程呢?
    在JDK的安装路径下,src.zip是全部的java源程序,通过此代码找到Thread中的start()方法的定义,可以发现此方法中使用了private native void start0();其中native关键字表示可以调用操作系统的底层函数,那么这样的技术成为JNI技术(java Native Interface)
    Runnable接口
    在实际开发中一个多线程的操作很少使用Thread类,而是通过Runnable接口完成。
    但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有。此时观察Thread类,有一个构造方法:public Thread(Runnable targer)此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多线程。(start()可以协调系统的资源):
    两种实现方式的区别和联系:
    在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
    避免点继承的局限,一个类可以继承多个接口。
    适合于资源的共享
    Runnable接口和Thread之间的联系:
    public class Thread extends Object implements Runnable
    发现Thread类也是Runnable接口的子类。

    1、新建状态(New):新创建了一个线程对象。

    private static void showThread() {
            //建立线程对象
            MyThread myThread = new MyThread();
            //开启线程
            myThread.start();
        }

    2、就绪状态(Runnable/ready):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

    private static void showRunnable() {
            //1,创建一个XXXRunnable对象
            MyRunnable myRunnable = new MyRunnable();
            //2,创建一个Thread对象,并将上面创建的XXXRunnable对象传入构造方法中
            //public Thread(Runnable target)构造方法
            //target是Runnable接口类型
            //可以接收实现了Runnable接口的任何一个类的对象
            //经常说成:它(指的就是Runnable接口)的实现类对象
            Thread t1 = new Thread(myRunnable);
            t1.start();
            System.out.println(Thread.currentThread().getName());
            System.out.println("主线程走完了");
        }

    3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
    runnable = ready 和 running的

    private static void showCreateMethod() {
            //匿名内部类+匿名对象的方式
            //调用start()方法开启线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        System.out.println("我是第一个线程");
                    }
                }
            }).start();
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    while (true) {
                        System.out.println("---------");
                    }
                }
            }.start();
            /**
             * 线程是抢占运行
             * 谁抢到了CPU的执行权,那么谁就运行
             */}

    4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。需要notifyAll唤醒
    yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可 执行状态后马上又被执行。

    public class PrinterDeadLock {
        private String s1 = "我是s1";
        private String s2 = "我是s2";
        public void p1() {
            synchronized (s1) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    //s1是锁对象,调用了s1锁对象的wait方法
                    //wait方法,会释放锁对象
                    //并且,使得线程进入阻塞状态
                    s1.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("s1锁住了p1");
                synchronized (s2) {
                    for (int i = 0; i < 10; i++) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("s2锁住了p1");
                    }
                }
            }
        }
        public void p2() {
            synchronized (s2) {
                System.out.println("s2锁住了p2");
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s1) {
                        System.out.println("s1锁住了p2");
                        //调用s1锁对象的
                        //notifyAll方法
                        //会唤醒被s1调用wait方法
                        // 进入阻塞状态的线程
                        s1.notifyAll();
                    }
                }
            }
        }
    }
    

    (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    这里写图片描述

        /**
         * synchronized,表示同步的意思
         *方法A执行完毕,方法B才跟着执行
         * 同步可以理解成等待某一事件结束才能开始做下一件事情
         * 同步是阻塞的,就是你做了这件事情,没做完就做不了别的事情
         * 异步就是做了一件事情没做完,就可以去做别的事情了
         */
        private static void showSynchronized() {
            SynDemo synDemo = new SynDemo();
            Thread t1 = new Thread(new Runnable() {
                 @Override
                 public void run() {
                     synDemo.del1();
                 }
             });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synDemo.show();
                }
            });
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synDemo.del2();
                }
            });
            Thread t4 = new Thread(new Runnable() {
                @Override
                public void run() {
                    synDemo.show1();
                }
            });
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }

    (三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

     private static void showJoin() throws InterruptedException {
            /**
             * join方法
             * t1.join()
             * 等待t1执行完,其他线程再执行
             * t1.join(500)
             * 等待t1执行500毫秒后,其他线程再执行
             */
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println(i);
                        try {
                            Thread.sleep(300);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            t1.start();
            t1.join(500);
            System.out.println("主线程执行完毕");
        }

    5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。

    sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。

    在调用sleep()方法的过程中,线程不会释放对象锁。

    而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

    获取对象锁进入运行状态。

    展开全文
  • 多线程1.线程和进程的定义1.2.线程进程的区别体现在几个方面:1.3....利用匿名内部类+runnable接口实现多线程优点:6.ThreadRunnable区别6.1.通过继承Thread类模拟售票通过结果可以看成是卖了10张票但是一共就5张

    1.线程和进程的定义

    • 进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
    • 线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位

    1.2.线程进程的区别体现在几个方面:

    • 因为进程拥有独立的堆栈空间和数据段,所以每当启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这对于多进程来说十分“奢侈”,系统开销比较大,而线程不一样,线程拥有独立的堆栈空间,但是共享数据段,它们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,切换速度也比进程快,效率高,但是正由于进程之间独立的特点,使得进程安全性比较高,也因为进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。一个线程死掉就等于整个进程死掉。

    • 体现在通信机制上面,正因为进程之间互不干扰,相互独立,进程的通信机制相对很复杂,譬如管道,信号,消息队列,共享内存,套接字等通信机制,而线程由于共享数据段所以通信机制很方便。

    • 属于同一个进程的所有线程共享该进程的所有资源,包括文件描述符。而不同的进程相互独立。

    • 线程又称为轻量级进程,进程有进程控制块,线程有线程控制块;

    • 线程必定也只能属于一个进程,而进程可以拥有多个线程而且至少拥有一个线程;

    • 简而言之:开启酷狗音乐只是一个进程,同时可以听歌和下载歌曲(2个线程)

    1.3.我们的理解:

    • 进程是指在系统中正在运行的一个应用程序;程序一旦运行就是进程,或者更专业化来说:进程是指程序执行时的一个实例。

    • 线程是进程的一个实体。

    • 进程——资源分配的最小单位,线程——程序执行的最小单位

    2.多线程的2种或者4种实现方法

    ps:网上说有4种实现方法,但是也有一部分人是持但对意见的,那么这4种方法究竟如何呢?

    2.1.Java多线程实现的方式有四种

    • 继承Thread类,重写run方法
    • 实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
    • 通过Callable和Future/FutureTask创建多线程
    • 通过线程池创建多线程

    补充:

    • 前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果。
    • 后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中

    3.多线程的创建之Thread的步骤

    1. 定义一个类继承Thread
    2. 重写run方法
    3. 创建子类对象,就是创建线程对象
    4. 调用start方法,开启多线程并执行,同时还会告诉jvm去调用run方法
    package com.Li.xc01;
    /**
     * @Description:通过继承thread实现多线程
     * @auther:Li Ya Hui
     * @Time:2021年4月20日下午7:39:10
     */
    public class JiSuanQi extends Thread {
    
    	@Override
    	public void run() {
    //			System.out.println("计算器:run()");
    //			System.out.println("当前线程的名字:"+Thread.currentThread().getName());
    		for (int i = 0; i < 10; i++) {
    			System.out.println("主函数的名字\t"+getName());
                //Thread.currentThread().getName()可以缩写,但是为了语义化,一般都要写
    		}
    	}
    	//此构造期为更改线程名字
    	public JiSuanQi(String name) 
    	{
    		super(name);
    	}
    }
    
    /**
     * @Description:	测试类 通过继承thread类实现多线程             多线程 之 Thread的步骤
     * @auther:Li Ya Hui
     * @Time:2021年4月20日下午7:17:50
     */
    public class Test {
    	public static void main(String[] args) {
    		
    		for (int i = 0; i < 10; i++) {
    			System.out.println("主函数的名字\t"+Thread.currentThread().getName());
    		}
    		
    		System.out.println("主函数001");
    		System.out.println("主函数002");
    		System.out.println("主函数003");
    		
    		//主函数的线程名字:main
    		System.out.println("当前线程的名字"+Thread.currentThread().getName());
    		
    		//开启多线程,创建子类对象
    		JiSuanQi jiSuanQi = new JiSuanQi("计算器线程");
    		
    		//当调用start方法的时候,jvm会自动执行run方法,
    		//其他非主函数的线程的名字:Thread-0...... 但是可以通过有参数构造器进行修改
    		jiSuanQi.start();
    	}
    }
    

    通过测试发现thread里的run方法不会因为main方法的结束而受到影响

    4.通过实现runnable接口实现多线程

    1. 定义类实现Runnable接口
    2. 覆盖/实现接口中的run方法
    3. 创建Thread类的对象
    4. 将Runnable接口的实现类对象作为参数传递给Thread类的构造函数
    5. 调用Thread类的start方法开启线程
    //Runable 接口  的实现类
    /**
     * @Description: 通过Runable实现类  给Thread传参数实现 多线程
     * @auther:Li Ya Hui
     * @Time:2021年4月20日下午8:34:21
     */
    public class Prims implements Runnable{
    	@Override
    	public void run() {
    		while (true)
    		{
    			try {
    				//线程睡眠 1000毫秒
    				Thread.sleep(1000);
    				System.out.println("当前线程的内容:"+Thread.currentThread().getName());
    			} catch (InterruptedException e) {//线程中断异常
    				//异常处理
    				System.out.println("当前"+Thread.currentThread().getName()+"线程终端异常");
    			}
    		}
    	}
    }
    //测试类
    package com.Li.xc02;
    /**
     * @Description: 测试  runnable  给Thread传参数实现 多线程
     * @auther:Li Ya Hui
     * @Time:2021年4月21日下午3:05:40
     */
    public class Test {
    
    	public static void main(String[] args) throws InterruptedException {
    		System.out.println("主线程执行的内容001");		
    		//实例化runnable,
    		Prims a = new Prims();
    		//参数形式传递给Thread
    		Thread TH = new Thread(a);
    		//主线程睡眠
    		Thread.sleep(2000);
    		System.out.println("主线程执行的内容002");		
    		//子线程开启
    		TH.start();		
    		System.out.println("主线程执行的内容003");
    	}
    }
    

    4.2.解释说明

    Thread类中包括构造函数Thread(Runnable target)和Thread(Runnable target,String name),可以床底Runnable接口,说明构造函数支持传入一个Runnable接口的对象。
    构造函数Thread(Runnable target)不光可以传入Runnable接口的对象,还可以传入一个Thread类的对象。这样的好处是可以完全将Thread对象中的run()方法交由其他线程进行调用。

    4.3.比较

    如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
    main函数,实例化线程对象也有所不同,
    extends Thread :t.start();
    implements Runnable : new Thread(t).start();
    使用Runnable,增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
    线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

    4.4.实现Runnable的原理

    • 为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢?

    • 实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖/实现Runnable接口中的run方法,将线程任务代码定义到run方法中。

    • 创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的实现对象,所以将这个实现类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确的得到要运行的线程的任务。

    • 简而言之:实现Runable接口进而实现接口中的run方法,然后创建实例化Thread类,将线程任务所在的对象/类以参数的形式传递给Thread的构造函数最终实现多线程

    4.5.实现Runnable的好处

    • 第二种方式,实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

    • 简而言之:避免了单继承的局限性,安全,耦合度低

    5.利用匿名内部类+runnable接口实现多线程

    package com.Li.xc02;
    
    
    /**
     * @Description: 利用匿名内部类+runnable接口实现多线程
     * @auther:Li Ya Hui
     * @Time:2021年4月21日下午6:49:12
     */
    public class Test02 {
    
    	public static void main(String[] args) {
    		
    		System.out.println("主函数线程打印:001");
    		
    		Thread thread = new Thread(new Runnable() 
    		{
    			@Override
    			public void run()
    			{
    				System.out.println("当前线程的名字为:"+Thread.currentThread().getName());
    			}
    		});
    		thread.start();
    		
    		System.out.println("主函数线程打印:002");
    
    	}
    }
    
    

    优点:

    1. 线程任务类只是实现了Runnable接口,可以继续继承其他类,而且可以继续实现其他的功能
    2. 同一个线程任务对象可以被包装成多个线程对象
    3. 适合多个相同的程序代码的线程去共享同一个资源
    4. 实现解棍操作,代码可以被多个线程共享,线程任务代码和线程独立

    6.Thread和Runnable的区别

    6.1.通过继承Thread类模拟售票

    package com.Li.xc03;
    /**
     * 
     * @Description:买票类   测试通过继承Thread类模拟售票
     * @auther:Li Ya Hui
     * @Time:2021年4月21日下午9:04:36
     */
    public class Mythread extends Thread{
    	public int tickets = 5;
    	
    	public void run() {
    		for (int i = 1; i < 10; i++) {
    			System.out.println("当前线程为:"+getName()+":"+(tickets--));
    		}
    	}
    	//线程添加名字  
    	public Mythread(String name) {
    		super(name);
    		// TODO Auto-generated constructor stub
    	}
    }
    
    package com.Li.xc03;
    /**
     * @Description: 测试类 测试通过继承Thread类模拟售票
     * @auther:Li Ya Hui
     * @Time:2021年4月21日下午9:13:41
     */
    public class Test {
    	public static void main(String[] args) {
    		Mythread myA = new Mythread("A窗口");
    		Mythread myB = new Mythread("B窗口");
    		myA.start();
    		myB.start();
    		//通过结果可以看成是卖了10张票但是一共就5张票,所以此时只能说明这种方式实现的时候是没有共享资源的
    	}
    }
    
    • 通过结果可以看成是卖了10张票但是一共就5张票,所以此时只能说明这种方式实现的时候是没有共享资源的 ( 没有共享tickets )

    6.2.通过实现Runnable接口实现售票

    可以实现共享资源的效果,但是会同时进行买票的问题,延伸出了互斥锁

    synchronized (this)//同步锁    //	mutex互斥 在此处是锁的效果,即互斥锁
    {
        if (tickets > 0) 
        {
        	System.out.println("当前线程的名字:" + Thread.currentThread().getName() + ":" + (tickets--));
        }
    }
    

    互斥锁使得,多个线程不可同时访问一个资源

    案例展示

    package com.Li.xc04;
    /**
     * @Description: 通过实现 Runnable接口  实现多线程-模拟售票
     * @auther:Li Ya Hui
     * @Time:2021年4月21日下午9:30:16 
     */
    public class Mythread implements Runnable {
    	
    	//总票数
    	public int tickets = 500;
    	
    	@Override
    	public void run() {
    		for (int i = 0 ;i<10000 ; i++)  {
    			//this 指代当前类的意思  在此处表示为给当前的类加上互斥锁的效果
    			synchronized (this)//同步锁    //	mutex互斥 在此处是锁的效果,即互斥锁
    			{
    				if (tickets > 0) {
    					System.out.println("当前线程的名字:" + Thread.currentThread().getName() + ":" + (tickets--));
    				}
    			}
    		}
    	}
    }
    
    package com.Li.xc04;
    /**
     * @Description: 测试类  测试Runnable的实现类运用多个线程来共享资源去买票,不会有数据读脏的可能
     * @auther:Li Ya Hui
     * @Time:2021年4月21日下午10:08:55
     */
    public class Test {
    
    	public static void main(String[] args) {
    		//实例化我的售票类
    		Mythread myRunThread1 = new Mythread();
    		
    		//实例两个线程  用来分工
    		Thread thread1 = new Thread(myRunThread1, "1号窗口");
    		Thread thread2 = new Thread(myRunThread1, "线程二");
    		
    		thread1.start();
    		thread2.start();
    		
    		//通过结果我们发现,会有数据读脏的可能性
    		//所以要使用互斥锁来避免同时读取数据问题
    	}
    }
    

    Runnable总结:

    • 实现Runnable接口比继承Thread类所具有的优势:
    • 适合多个相同的程序代码的线程去处理同一个资源
    • 可以避免java中的单继承的限制
    • 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
    • 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
    展开全文
  • java中实现多线程有两种方法:一种是继承Thread类,另一种是实现Runnable接口。
  • 实现多线程主要的两种方式一种是extends Thread,一种是 implements Runnable,然后重写或者实现run方法,然后调用start的方法,实现多线程。 切记要调用start方法,如果直接调用run方法则就不是多线程了,至于...
  • 实现多线程的两种方式: 继承Thread与实现Runnable接口。  实际应用中以实现Runnable接口为主。 两者的主要区别在于,1,Runnable接口可以实现资源共享;2,避免单点继承的局限性。 比如网上有卖票的例子来...
  • 多线程 Thread VS Runnable

    千次阅读 2016-03-07 00:18:18
    那么这两种实现多线程的方式在应用上有什么区别呢?  为了回答这个问题,我们可以通过编写一段代码来进行分析。我们用代码来模拟铁路售票系统,实现通过四个售票点发售某日某次列车的100张车票,一个售票点用...
  • 通过继承Thread类或者实现Runnable接口、Callable接口都可以实现多线程,不过实现Runnable 接口实现Callable接口的方式基本相同,只是Callable接口里定义的方法返回值,可以声明抛出异 常而已。因此将实现Runnable...
  • 多线程中实现Runnable与继承Thread区别 Runnable本质是先创建任务,然后通过线程来分配任务。 实现代码如下: public class Demo { public static void main(String[] args) throws IOException, ...
  • java多线程 ThreadRunnable

    千次阅读 2012-09-19 12:00:19
    Java中实现多线程有两种途径:继承Thread类或者实现Runnable接口。Runnable是接口,建议用接口的方式生成线程,因为接口可以实现多继承,况且Runnable只有一个run方法,很适合继承。在使用Thread的时候只需继承...
  • Java 多线程ThreadRunnable 区别
  • java多线程需要掌握的内容有: 1)ThreadRunnable区别 2)线程的状态及其之间的转换 ...在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
  • 多线程ThreadRunnable

    2014-10-16 19:02:32
    在Java实现多线程的程序中,虽然Thread类实现了Runnable接口,但是操作线程的主要方法并不在Runnable接口中,而是在其子类Thread中,比如start()这个方法就只能通过Thread实例化才能使用,用Runnable的话则会出错...
  • 线程Thread与Runnable接口

    千次阅读 2017-11-21 17:32:50
    一、首先,线程线程类的区别线程是硬件资源CPU调度任务执行的最小单元,是一个抽象的概念;线程类本质上就是一串可执行的代码,在Java中就是Thread.class文件。 Thread线程的定义如下public class Thread extend
  • 多线程ThreadRunnable区别

    万次阅读 多人点赞 2019-06-17 15:13:43
    文章目录线程?实现方式Thread类 线程?  线程是进程中独立运行的子任务,比如我们运行的QQMuic.exe的时候,然后就会有很多的子任务,而且不同... 多线程的编程方式有两种:一是集成Thread类,另一种是实现Runnab...
  • 我们都晓得java实现线程2种方式,一个是继承Thread,另一个是实现Runnable。 模拟窗口买票,第一例子继承thread,代码如下 [code="java"]package thread; public class ThreadTest { public ...
  • 线程2 Java多线程实现2.1 继承Thread类实现多线程2.2 实现Runnable接口来实现多线程2.3 继承Thread实现Runnable借口的区别 1 进程线程 1.1 进程线程的概念 什么是进程?   进程: 操作系统中一个程序的...
  • 子类继承Thread类具备多线程能力 启动线程:子类对象.start() 不建议使用:避免OOP单继承局限性 实现Runnable接口 实现接口Runnable接口具有多线程能力 启动线程:传入目标对象+Thread对象.start() new ...
  • 编写多线程程序一般有三种方法,Thread,Runnable,Callable。 1. Runable Runnable是个接口,使用很简单: 1. 实现该接口并重写run方法2. 利用该类的对象创建线程3. 线程启动时就会自动调用该对象的run方法 ...
  • 创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成: class ...
  • 这是一道面试题,创建多线程时,使用继承Thread类和实现Runnable接口有哪些区别呢? 一、Thread 先来看看Thread类和其中的start()方法 class Thread implements Runnable{.....} // 可见,Thread类实现了Runnable...
  • Java的多线程Thread实现,跟runnable没有太大关系。 android中因为需要多线程交换数据出现了handler+message+thread实现多线程数据通信。就hanlder本身而言并不是实现多线程。 因为handler+message+thread手写比较...
  • Thread才是Java语言对线程的抽象, Runnable 是对任务的抽象,对业务逻辑的抽象 另外,Thread内部其实是实现了Runnable接口的,是对Runnable的扩展 实现Runnable和继承Thread相比哪个更好? a.从代码的角度, Java只能单...
  • 我在上一个博客说了两种实现多线程的方法,实现Runnable接口继承Thread类,表面上看他们都没有什么区别,但在实际使用中继承Thread的较少,实现Runnable的较多。这说明他们之间还是有很大的区别的,下面我们看一下...
  • java 多线程之继承Thread类实现创建多线程1.Java 多线程Thread类2.继承Thread类实现创建多线程3.Thread类常用的方法 1.Java 多线程Thread类 Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类...
  • 多线程实现接口Runnable和继承Thread区别" title="Java 多线程实现接口Runnable和继承Thread区别" style="margin:0px; padding:0px; border:0px; list-style:none"> 实现Runnable接口: 多线程实现接口Runnable...
  • 首先讲一下进程和线程区别  进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。  线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和...
  • 前一章简单介绍了什么是进程和线程,本章将重点介绍java中的线程ThreadRunnable Thread和Runnable简介 Thead类是JDK为我们提供的基于操作系统的线程体系统一接口(操作系统负责线程的管理)。一个Thread对象和操作...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 268,939
精华内容 107,575
关键字:

多线程thread与runnable的区别