zoukankan      html  css  js  c++  java
  • 多线程基础(创建、常用方法以及线程的生命周期和风险)

    线程的创建

    1. 写一个类去继承Thread类,重写run()方法
    2. 写一个类去实现Runable接口
    public class MyThread extends Thread {
        @Override
        public void run() {
            for (int i=1;i<=100;i++){
                System.out.println(i+"子线程启动。。。。。。。。。子线程");
            }
        }
    }
    public class TestCreateThread {
        public static void main(String[] args) {
            System.out.println("main方法启动。。。。。。。。。。主线程");
            //创建子线程
            Thread thread=new MyThread();
            Thread thread1=new Thread(()->{
                System.out.println("接口创建线程");
            });
            thread1.run();
            //启动线程
            thread.start();
            for (int i=0;i<100;i++){
                System.out.println(i+"main方法启动。。。。。。。。。。主线程");
            }
            System.out.println("主线程的逻辑。。。。。");
        }
    }

    Thread类的常用方法

    currentThread()方法

    Thread.currentThread()方法可以获得当前线程 ,Java 中的任何一段代码都是执行在某个线程当中的. 执行当前代码的线程就是当前线程.同一段代码可能被不同的线程执行 , 因此当前线程是相对的,Thread.currentThread()方法的返回值是在代码实际运行时候的线程对象

    setName()/getName()

    thread.setName(线程名称), 设置线程名称,thread.getName()返回线程名称,通过设置线程名称,有助于程序调试,提高程序的可读性, 建议为每个线程都设置一个能够体现线程功能的名称

    isAlive()

    thread.isAlive()判断当前线程是否处于活动状态,活动状态就是线程已启动并且尚未终止

    sleep()

    Thread.sleep(millis); 让当前线程休眠指定的毫秒数

    getId()

    hread.getId()可以获得线程的唯一标识
    注意:
    某个编号的线程运行结束后,该编号可能被后续创建的线程使用,重启的 JVM 后,同一个线程的编号可能不一样

    yield()

    Thread.yield()方法的作用是放弃当前的 CPU 资源

    setPriority()

    thread.setPriority( num ); 设置线程的优先级,java 线程的优先级取值范围是 1 ~ 10 , 如果超出这个范围会抛出异常 IllegalArgumentException.
    在操作系统中,优先级较高的线程获得 CPU 的资源越多,线程优先级本质上是只是给线程调度器一个提示信息,以便于调度器决定先调度哪些线程. 注意不能保证优先级高的线程先运行.
    Java 优先级设置不当或者滥用可能会导致某些线程永远无法得到运行,即产生了线程饥饿.线程的优先级并不是设置的越高越好,一般情况下使用普通的优先级即可,即在开发时不必设置线程的优先级
    线程的优先级具有继承性, 在 A 线程中创建了 B 线程,则 B 线程的优先级与 A 线程是一样的

    interrupt()

    中断线程.注意调用 interrupt()方法仅仅是在当前线程打一个停止标志,并不是真正的停止线程,搭配isInterrupt()使用

    setDaemon()

    Java 中的线程分为用户线程与守护线程
    守护线程是为其他线程提供服务的线程,如垃圾回收器(GC)就是一个典型的守护线程
    守护线程不能单独运行, 当 JVM 中没有其他用户线程,只有守护线程时,守护线程会自动销毁, JVM 会退出

     示例:

    package com.edu.creatThread;
    
    /**
     * @作者 five-five
     * @创建时间 2020/9/13
     */
    public class DemonThread extends Thread {
        @Override
        public void run() {
            super.run();
            while(true){
                System.out.println("守护线程启动。。。。。。");
            }
        }
    }
    -------------------------------------------------------------------------
    package com.edu.creatThread;
    
    /**
     * @作者 five-five
     * @创建时间 2020/9/13
     */
    public class TestDemon {
        public static void main(String[] args) {
            DemonThread demonThread = new DemonThread();
            demonThread.setDaemon(true);//设置线程为守护线程
            for (int i=0;i<1;++i){
                System.out.println("main线程在跑。。。。。");
            }
            demonThread.start();
    
        }
    }

    多线程的生命周期

    线程的生命周期是线程对象的生老病死,即线程的状态
    线程生命周期可以通过 getState()方法获得 , 线程的状态是Thread.State 枚举类型定义的

    NEW,新建状态.

    创建了线程对象,在调用 start()启动之前的状态

    RUNNABLE,可运行 状态

    它 是一 个复 合状 态 , 包 含 :READY 和RUNNING 两个状态. READY 状态该线程可以被线程调度器进行调度使它 处 于 RUNNING 状 态 , RUNING 状 态 表 示 该 线 程 正 在 执 行 .
    Thread.yield()方法可以把线程由 RUNNING 状态转换为 READY 状态

    BLOCKED 阻塞状态

    线程发起阻塞的 I/O 操作,或者申请由其他线程占用的独占资源,线程会转换为 BLOCKED 阻塞状态. 处于阻塞状态的线程不会占用 CPU 资源. 当阻塞 I/O 操作执行完,或者线程获得了其申
    请的资源,线程可以转换为 RUNNABLE.

    WAITING 等待状态

    线程执行了 object.wait(), thread.join()方法会把线程转换为 WAITING 等待状态, 执行 object.notify()方法,或者加入的线程执行完毕,当前线程会转换为 RUNNABLE 状态

    TIMED_WAITING 状态

    与 WAITING 状态类似,都是等待状态.区别在于处于该状态的线程不会无限的等待,如果线程没有在指定的时间范围内完成期望的操作,该线程自动转换为 RUNNABLE

    TERMINATED 终止状态

    线程结束处于终止状态

    线程生命示例图:

     多线程编程存在的问题与风险:

    线程安全(Thread safe)问题.

    多线程共享数据时,如果没有采取正确的并发访问控制措施,就可能会产生数据一致性问题,如读取脏数据(过期的数据), 如丢失数据更新

    线程活性(thread liveness)问题.

    由于程序自身的缺陷或者由资源稀缺性导致线程一直处于非 RUNNABLE 状态,这就是线程活性问题

    常见的活性故障有以下几种:

    1.   死锁(Deadlock). 类似鹬蚌相争.
    2.   锁死(Lockout), 类似于睡美人故事中王子挂了
    3.   活锁(Livelock). 类似于小猫咬自己尾巴
    4.   饥饿(Starvation).类似于健壮的雏鸟总是从母鸟嘴中抢到食物.

    上下文切换(Context Switch).

    处理器从执行一个线程切换到执行另外一个线程

    可靠性

    可能会由一个线程导致 JVM 意外终止,其他的线程也无法执行

  • 相关阅读:
    JS 给li标签下所有a标签添加点击事件并添加和删除样式
    Linux简介及常用命令
    简易计算器
    登陆窗口小项目
    时间工具类
    String类的常用方法(附带练习)
    java-自定义异常
    Java小练习
    Java-接口练习1
    动态加载js
  • 原文地址:https://www.cnblogs.com/five-five/p/13660776.html
Copyright © 2011-2022 走看看