zoukankan      html  css  js  c++  java
  • 线程入门

    线程的几个属性

    线程的属性包括线程的编号(ID),名称(Name),线程类别(Daemon),和优先级(Priority);

    属性 属性类型及用途 只读属性 重要注意事项
    编号(ID) 类型:long。用于标识不同的线程,不同线程有不同编号 某个编号的线程运行结束后,该编号可能被后续创建的线程使用,不同线程拥有的编号虽然不同,但是这种编号的唯一性只在Java虚拟机的一次运行有效。也就是说重启一个Java虚拟机后,某些线程的编号可能与上次Java虚拟机运行的某个线程的编号一样,因此该属性的值不适合用作唯一标识。
    名称(Name) 类型:String,区分不同线程,默认格式:“Thread-线程编号”,如“Thread-0” Java并不禁止同名,设置线程名称属性有助于代码调试和问题定位。
    线程类别(Daemon) 类型:boolean,值为true标识相应的线程为守护线程,否则为用户线程,该属性的默认值与相应线程的父线程的该属性值相同。 该属性必须在该线程启动之前设置,即对setDaemon方法的调用必须在start方法的调用之前;否则会抛出IllegalThreadStateException异常,负责一些关键任务处理的线程不适合设置为守护线程。
    优先级(Priority) 类型:int。该属性本质上是给线程调度器的提示,用于表示应用程序希望哪个线程得到优先运行。Java定义了1-10的10个优先级。默认值一般为5; 一般使用默认优先级即可。不恰当的设置该属性可能导致严重的问题(线程饥饿)

    线程创建的几种方式

    Thread

    继承Thread,重写run方法

    
    public class ThreadDemo extends Thread {
    
        @Override
        public void run() {
            System.out.println("Thread Demo One");
        }
    
        public static void main(String[] args) {
            //方式一
            ThreadDemo threadDemo=new ThreadDemo();
            threadDemo.start();
            //方式二
            new Thread(){
                @Override
                public void run() {
                    System.out.println("Thread Demo Two");
                }
            }.start();
            //方式三
            new Thread(() -> System.out.println("Thread Demo Three")).start();
        }
    }
    
    

    说明: 暂时列了这三种方式,其中方式二,三是一样的代码,Java8中的函数式编程可以将方式二精简成方式三;

    注意:

    1. 是调用Thread的start方法才是启动线程,直接调用run方法只是方法调用,并不会新开一个线程;
    2. start方法不可多次调用,在调用start方法后再次调用会抛出IllegalThreadStateException异常;

    Runnable

    实现Runnable的run方法

    
    public class RunnableDemo {
        public static void main(String[] args) {
            new Thread(new RunnableDemoRun()).start();
        }
    
    }
    class RunnableDemoRun implements Runnable{
    
        @Override
        public void run() {
            System.out.println("Runnable Demo");
        }
    }
    
    

    Callable

    1. Future
    
    public class CallableDemo {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //构造线程池
            ExecutorService executorService = Executors.newCachedThreadPool();
            //创建实例
            CallableDemoRun callableDemoRun = new CallableDemoRun();
            //执行
            Future<String> submit = executorService.submit(callableDemoRun);
            // 注意调用get方法会阻塞当前线程,直到得到结果。
            // 所以实际编码中建议使用可以设置超时时间的重载get方法。
            System.out.println(submit.get());
        }
    }
    class CallableDemoRun implements Callable<String> {
        @Override
        public String call() throws Exception {
            // 沉睡一秒
            Thread.sleep(1000);
            System.out.println("Callable Demo Run");
            return "SUCCESS";
        }
    }
    
    
    1. FutureTask
    
    public class CallableDemoOne {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //创建线程池
            ExecutorService executorService = Executors.newCachedThreadPool();
            //实例化线程
            CallableDemoRunOne callableDemoRunOne = new CallableDemoRunOne();
            //封装进FutureTask
            FutureTask<String> stringFutureTask = new FutureTask<>(callableDemoRunOne);
            //执行
            executorService.submit(stringFutureTask);
            System.out.println(stringFutureTask.get());
        }
    }
    class CallableDemoRunOne implements Callable<String>{
        @Override
        public String call() throws Exception {
            // 沉睡一秒
            Thread.sleep(1000);
            System.out.println("Callable Demo Run");
            return "SUCCESS";
        }
    }
    
    

    问题

    Thread类的几个常用方法

    • currentThread():静态方法,获取当前正在执行的线程对象的引用

    • start():开始执行线程的方法,Java虚拟机会执行线程内的run方法

    • yield():yield在英语里有放弃的意思,同样,这里的yield()指的是当前线程愿意让出对当前处理器的占用。这里需要注意的是,就算当前线程调用了yield()方法,程序在调度的时候,也还有可能继续运行这个线程的;

    • sleep():静态方法,使当前线程睡眠一段时间;

    • join():使当前线程等待另一个线程执行完毕之后再继续执行,内部调用的是Object类的wait方法实现的;

    sleep与wait有什么区别

    • sleep方法是Thread的一个静态类方法,wait方法是object的实例

    • 调用sleep方法过程中,线程不会释放当前持有的锁资源;而调用wait方法,会使线程处于等待(阻塞)状态,并且释放所持有的对象的锁;

    • 调用sleep()方法需要指定时间,到期后线程会自动唤醒;而调用wait方法的线程需要手动唤醒;

    Thread类与Runnable接口的比较

    • 由于Java‘单继承,多实现’的特性,Runnable接口使用起来比Thread更灵活;

    • Runnable接口出现更符合面向对象,将线程单独进行对象的封装。

    • Runnable接口出现,降低了线程对象和线程任务的耦合性。

    • 如果使用线程时不需要使用Thread类的诸多方法,显然使用Runnable接口更为轻量。

    Callable,Runnable和Thread区别

    • Runnable与Callable是一个接口,Thread是Runnable的实现类

    • Runnable和Thread均无返回值,Callable有返回值

    • Runnable和Thread线程内不能抛出异常,需内部处理异常,Callable可抛出异常

    Future与FutureTask

    • Future是接口类,FutureTask是实现的RunnableFuture接口的,而RunnableFuture接口同时继承了Runnable接口和Future接口

    参考:

    1. 《Java多线程编程实战指南-核心篇》
    2. RedSpider社区
  • 相关阅读:
    中国首届React开发者大会 8月18日 广州举行
    事件循环:Flutter 中代码是如何执行和运行的
    大前端趋势所向:这么多跨端技术,为什么选择 Flutter?
    通往大前端的一把关键钥匙 Flutter
    如何选一部好的手机?性价比高的智能手机推荐,2020智能手机排行榜!
    智能手机边充电边玩对电池有什么损害吗?
    你的智能手机究竟能用多久?
    新型添加技术
    智能手机
    姐姐不愧是姐姐,快看《乘风破浪的姐姐》
  • 原文地址:https://www.cnblogs.com/guoyuchuan/p/11761927.html
Copyright © 2011-2022 走看看