zoukankan      html  css  js  c++  java
  • java中多线程

    线程

    什么是线程:

     线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源
    

    表面上是多线程其实是cpu快速轮流切执行

    多线程(并行和并发)

    1. 并行:两个任务同事进行,就是甲任务执行的同时,乙任务也在执行(需要多核)
    2. 并发:两个任务都请求运行,而处理器只能接受一个任务,就把这两个任务安排轮流执行。由于时间间隔很短,使人感觉两个任务都在运行

    多线程(java程序运行的原理)

    java命令会启动jvm等于启动了一个应用程序(一个进程)。该进程会自动启动“主线程”,主线程去调用main方法
    

    启动jvm是单线程的么?

    不是,是多线程的。至少会启动垃圾回收线程和主线程
    

    可通过下面代码来验证,主线程和垃圾回收线程在互相抢占资源

    public class TestThread {
    
        public static void main(String[] args) {
            //4.创建Thread的子类对象
            MyThread myThread = new MyThread();
    
            //5.启动线程,注意这里使用的是start而不是run方法
            myThread.start();
    
            for (int i = 0; i < 10000; i ++) {
                System.out.println("This is main thread");
            }
        }
    
    
    }
    
    //1.继承Thread
    class MyThread extends  Thread{
    
        //2.重写run方法
        @Override
        public void run() {
            super.run();
            //3.线程方法中要执行的代码,可以根据自己的需求填写
            for(int i = 0 ; i < 10000 ; i ++ ) {
                System.out.println("This is MyThread thread ");
            }
        }
    }
    

    java中如何创建多线程

    (1)继承Thread类并调用start方法

    Thread实现了Runnable接口
    要实现多线程,就要成为thread的子类,并且重写run方法。注意在启动线程的时候,调用的不是run方法而是start方法。如果调用run方法,那么相当于一个普通方法并不会开启线程

    public class Thread implements Runnable 
    
    public class TestThread {
    
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            //注意这里使用的是start而不是run方法
            myThread.start();
    
            for (int i = 0; i < 10000; i ++) {
                System.out.println("This is main thread");
            }
        }
    
    
    }
    
    class MyThread extends  Thread{
    
        @Override
        public void run() {
            super.run();
    
            for(int i = 0 ; i < 10000 ; i ++ ) {
                System.out.println("This is MyThread thread ");
            }
        }
    }
    

    (2)实现runnable接口,并重写run方法

    Runnable中只有一个方法run(),而线程启动方法存在与Thread中,
    那么我们在最终启动线程的时候,势必是要通过Thread的子类对象去启动线程的
    
    public class TestRunnable {
    
        public static void main(String[] args) {
            //4.创建Thread的子类对象
            Runnable myRunnable = new MyRunnable();
    
            //5.启动线程,创建Thread并把runnable的子类作为构造参数
            new Thread(myRunnable).start();
    
            for (int i = 0; i < 10000; i ++) {
                System.out.println("This is main thread");
            }
        }
    
    
    }
    //1.实现runnable接口
    class MyRunnable implements Runnable {
    
        //2.重写run方法
        @Override
        public void run() {
            //3.线程方法中要执行的代码,可以根据自己的需求填写
            for(int i = 0 ; i < 10000 ; i ++ ) {
                System.out.println("This is MyRunnable thread ");
            }
        }
    }
    
    

    实现Callable接口

    要实现线程,除了继承thread和runnable,还可以实现Callable接口。Callable接口提供了一个call()方法可以作为线程执行体,和run()的作用一样。但call()方法比run()方法多了返回值,call()方法可以声明抛出的异常。那么我们如何开启Callable线程呢?因为Callable接口不是Runnable接口的子接口,所以Callable对象不能作为Thread的构造参数。Java提供了另一个接口RunnableFuture接口,该接口实现了Runnable, Future接口,意味着我们可以把RunnableFuture的实现对象作为构造参数船体给Thread。RunnableFuture接口提供FutureTask实现类,我们可以通过调用FutureTask的get()方法,来获取call()的返回值

    1. 实现Callable接口
    2. 重写call方法,相当于thread中的run方法。不同的是call方法允许有返回值
    3. 把Callable实现类对象作为构造参数传入FutureTask创建FutureTask对象。
    4. 把FutureTask对象作为构造参数传入Thread,并开启线程
    public class CallableDemo {
    
        public static void main(String[] args) {
            //3.把Callable实现类对象作为构造参数传入FutureTask创建FutureTask对象。
            FutureTask<UUID> futureTask = new FutureTask<UUID>(new MyCallable());
            //4.把FutureTask对象作为构造参数传入Thread,并开启线程
            new Thread(futureTask).start();
            try {
                System.out.println(futureTask.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
    
    //1. 实现**Callable**接口
    class MyCallable implements Callable<UUID> {
    
        //2.重写**call**方法,相当于thread中的run方法。不同的是call方法允许有返回值
        @Override
        public UUID call() throws Exception {
            //生成随机数
            return UUID.randomUUID();
        }
    }
    

    继承Thread,实现Runnable和Callable的区别

    从源码的实现上

    继承Thread

    子类重写Thread中的run()方法,调用start()方法,jvm会自动调用子类的run()

    实现Runnable

    new Thread(myRunnable)在Thread的构造函数中参入runnable的引用,然后传给thread的成员变量target。在Thread run()方法中判断了如果target不为空,就调用子类的run方法

        public void run() {
        if (this.target != null) {
            this.target.run();
        }
    

    实现Callable接口

    实现Callable接口重写Call()方法,并且可以提供线程返回值,也可以抛出异常。最终通过Runnable的子接口RunnableFuture的实现类FutureTask,传给Thread的成员变量target。

    从使用上和拓展上

    继承Thread

    1. 优点:直接调用thread中的start()方法,十分简单
    2. 缺点:java只支持单继承,如果子类继承了thread无法再继承其他类

    实现Runnable

    1. 优点:java可以多实现
    2. 缺点:代码书写比较复杂,不能直接调用start()

    实现Callable

    1. 优点:java可以多实现,可以抛出异常,可以有返回值
    2. 缺点:代码书写比较复杂
  • 相关阅读:
    Python 函数 切片 迭代 列表生成器
    Python中各种集合 list tuple set dict
    Python学习 常识+基础基础
    《零基础学习Python》01
    原生API实现拖拽上传文件实践
    美团点评面试题小结(测试开发和前端开发)
    从实践的角度理解cookie的几个属性
    一道javascript面试题(闭包与函数柯里化)
    marked插件在线实时解析markdown的web小工具
    Github Page+Bmob实现简单动态功能
  • 原文地址:https://www.cnblogs.com/amberbar/p/9695787.html
Copyright © 2011-2022 走看看