线程的生命历程

线程的五大状态

  • 创建状态:简而言之,当创建线程对象的代码出现的时候,此时线程就进入了创建状态。这时候的线程只是行代码而已。只有调用线程的start()方法时,线程的状态才会改变,进入就绪状态
  • 就绪状态:在这个状态下的线程,已经做好了随时运行的准备,但是并不意味着会立刻开始运行。还需要等待CPU的随机调度,随机运行只有当线程被CPU调度运行成功,此时的线程才算是进入下一个状态——运行状态。
  • 运行状态:线程处于运行状态,主要是在运行线程中的代码块。
  • 阻塞状态:在线程运行过程中,当线程代码块中调用了线程的sleep(),yield(),同步锁定或者其他使线程阻塞的方法,此时的线程无法继续运行下去,进入了阻塞状态(线程代码块的自身逻辑混乱也可以使线程阻塞)。当造成线程阻塞的阻塞事件解决之后,线程不会回到运行状态,而是回到就绪状态,再次等待CPU的调度运行。需要注意的是,阻塞并不意味着线程运行终止
  • 死亡状态当线程成功运行完所有的代码之后,线程就结束了,也进入了死亡状态。线程一旦死亡,就无法再次启动,注意这里和阻塞状态的不同。同样的,当线程运行一半的时候被强行结束终止,也算进入死亡状态,也无法被再次启动。

线程的方法

Java中的thread类自带有线程的一些方法,这些方法可以让线程睡眠,插队,提高线程调度的优先级等等,它们提供了改变线程状态的操作手段。(不过在JDK帮助文档中,一些方法已经不推荐使用)

线程方法中的一些有趣的地方

  • 线程睡眠是以毫秒为单位的。一秒等于一千毫秒。一般在测试程序中调用睡眠方法,是为了提高程序问题的发生性,或者说为了发现bug

  • 线程停止,由于Java中自带的停止方法不太好用,所以一般都是自己写一个停止的方法,标定一个布尔类型的Flag作为线程执行的标志,当flag为真时线程运行,当flag为假时线程停止。

  • 线程礼让是将正在运行的线程暂停回到就绪状态,而不是变为阻塞状态。有趣的是礼让不是一定会成功的,因为线程由就绪状态进入运行状态是由CPU随机调度的。所以礼让的线程有可能在下次的调度中再次提前调度,提前运行。

  • 线程插队(join方法),强制阻塞其他线程,只有插入的线程执行完成之后,其他线程才能继续执行

  • 线程虽然有优先级的区别(1-10),但是在实际运行中还是得看CPU的心情调度运行,优先级高只是被调度的概率高一点。Java中自带有线程优先级的查看和改变方法(线程的优先级设置最好在线程启动之前)

    public class ttp {
    public static void main(String[] args) {
    //主线程的默认优先级
    System.out.println(Thread.currentThread().getName()+"--->" + Thread.currentThread().getPriority());
    MyPriorty mm = new MyPriorty();
    Thread t1 = new Thread(mm);
    Thread t2 = new Thread(mm);
    Thread t3 = new Thread(mm); t1.setPriority(10);
    t1.start(); t2.setPriority(4);
    t2.start(); t3.setPriority(6);
    t3.start(); }
    } //Runnable接口实现接口,run方法为打印线程名称和线程的优先级
    class MyPriorty implements Runnable{
    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+"--->" + Thread.currentThread().getPriority());
    }
    }
    //这里的输出有多种结果,因为优先级只是增加了线程被调度运行的机率
  • 用户线程和守护线程。守护线程的作用是保证用户线程的执行过程正常,例如Java中的内存回收线程和后台记录操作日志等等,这些都是守护线程。虚拟机必须等待用户线程执行完毕,不用等待守护线程执行完毕。当用户线程完成后,虚拟机就自动关闭,守护线程也就自动死亡了。

    //Java的Thread类自带设置守护线程的方法
    Thread.setdaemon(true) //设置为守护线程
    //一般我们创建的线程默认都是用户线程
  • 线程同步。线程同步是出现多个线程访问同一个对象并都想对其进行操作的时候必须考虑的问题。不进行线程同步(并发)控制的多线程是不安全的。


    //线程不安全,出现了-1张票以及有两个线程拿到同一张票的错误,所以这是一个不安全的线程
    public class test05 { public static void main(String[] args) {
    buyTicket b1 = new buyTicket();
    Thread t1 = new Thread(b1,"you");
    Thread t2 = new Thread(b1,"i");
    Thread t3 = new Thread(b1,"he");
    Thread t4 = new Thread(b1,"she");
    t1.start();
    t2.start();
    t3.start();
    t4.start(); }
    } class buyTicket implements Runnable{
    //剩余票数
    private int ticketNums = 12;
    private boolean flag = true; @Override
    public void run() {
    while(flag){
    buy();
    }
    } private void buy(){
    if(ticketNums <= 0){
    flag = false;
    return;
    }
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "买到了第" + ticketNums-- + "张票");
    }
    }

线程同步

线程同步实质上是一个等待机制。线程同步时会将多个线程放入对象等待池中进行排队(队列),等待前一个线程执行操作完毕,再有下一个线程进行执行操作。每个对象都有一个独有的锁(排他锁),每个线程执行时都会获得对象的排他锁,这样只有获得锁的线程可以对对象进行操作,执行结束后排他锁被下一个线程获得。总结来说,线程同步的形成条件就是:队列+锁

在访问时加入锁机制synchronized,当一个线程获得对象得排他锁,独占资源,其他线程必须等待,使用后释放锁即可

线程同步也有一些存在的问题(大部分是以牺牲性能以保证安全)

  • 一个线程持有锁会导致其他所有需要此锁的线程挂起
  • 在多线程竞争下,加锁,释放锁会导致较多的上下文切换和调度延时,引起性能问题
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题

一般来说,synchronized是方法声明中添加,默认对方法中的this对象资源添加锁。如果要对其他共享资源对象进行锁定,则要使用同步监视器

  • 一号线程访问,锁定监视器,开始执行中间的代码
  • 二号线程访问,发现监视器被锁,无法访问,挂起
  • 一号线程执行完毕,解锁监视器
  • 二号线程访问,监视器无锁,锁定并执行代码
public void xxx(){
//其中ob就是想要锁住的任意的共享资源对象
//代码块是放在同步监视器中的
synchronized(obj){
....
}
}

需要注意的是,这样的锁理论上是可行的 ,但是在实际运行中虽然加了锁,但是还是有可能出现不安全的现象

"本站所有文章均为原创,欢迎转载,请注明文章出处:Thales_ZeeWay百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。"

作者:Thales_ZeeWay

链接:Java线程状态及同步锁

来源:博客园


著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Java线程状态及同步锁的更多相关文章

  1. java线程中的同步锁和互斥锁有什么区别?

    两者都包括对资源的独占. 区别是 1:互斥是通过竞争对资源的独占使用,彼此没有什么关系,也没有固定的执行顺序. 2:同步是线程通过一定的逻辑顺序占有资源,有一定的合作关系去完成任务.

  2. Java线程状态Jstack线程状态BLOCKED/TIMED_WAITING/WAITING解释

    一.线程5种状态 新建状态(New) 新创建了一个线程对象. 就绪状态(Runnable) 线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运行,等待获 ...

  3. Java线程状态及 wait、sleep、join、interrupt、yield等的区别

    Java中的线程状态(详见Java线程状态及转换-MarchOn): wait:Object类的实例方法,释放CPU执行权,进入等待状态,直到  被中断.被拥有该对象锁的线程唤醒(notify或not ...

  4. Java线程状态切换以及核心方法

    1.Java线程状态 1.1 线程主要状态 ①初始(NEW):新创建了一个线程对象,但还没有调用start()方法.②运行(RUNNABLE):Java线程中将就绪(ready)和运行中(runnin ...

  5. Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程

    下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...

  6. 浅谈 Java线程状态转换及控制

    线程的状态(系统层面) 一个线程被创建后就进入了线程的生命周期.在线程的生命周期中,共包括新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead)这五 ...

  7. Java线程状态及切换

    Java线程状态及切换 一.什么是Java线程状态 在Java程序中,用于描述Java线程的六种状态: 新建(NEW):当前线程,刚刚新建出来,尚未启动. 运行(RUNNABLE):当前线程,处于竞争 ...

  8. Java线程状态转换

    前言:对于Java线程状态方面的知识点,笔者总感觉朦朦胧胧,趁着最近整理资料,将Java线程状态方面的知识点总结归纳,以便加深记忆. 1.Java线程状态值 在Thread类源码中通过枚举为线程定义了 ...

  9. 从源码看java线程状态

    关于java线程状态,网上查资料很混乱,有的说5种状态,有的说6种状态,初学者搞不清楚这个线程状态到底是怎么样的,今天我讲一下如何看源码去解决这个疑惑. 直接上代码: public class Thr ...

随机推荐

  1. First Linux Centos 7.2 rpm 安装MySQL 5.7

    服务器需要换python环境,手贱重装了,今天凑巧需要测试数据库,花了一个小时搞了一下MySQL安装. 1.删除原有Mariadb 说明:目前centos默认的MySQL是Mariadb,由于习惯了M ...

  2. c++ 的学习笔记 第一集cim cout

    1. 你要用这个东西,所以得有包含它得头文件,就像java 你要用某个模块,你得包含这个模块 模块化??单片机里面学的模块化(可以在vs里面实现) 2. 当我把注册表regedit 程序删除之后成功了 ...

  3. 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析OpenHarmony源码 | v13.02

    百篇博客系列篇.本篇为: v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51.c.h .o 几点说明 kernel_liteos_a_note | 中文注解鸿蒙内核 ...

  4. Android12系统源码分析:NativeTombstoneManager

    Android12系统源码分析:NativeTombstoneManager 概述 android12新增的system_server进程(LocalService)本地服务,用于管理native t ...

  5. SpringBoot入门报错 Whitelabel Error Page的总结

    刚入门SpringBoot,编写helloControl类,去访问本地端口,无缘无故报了这个错误 Whitelabel Error Page 总结了下,目前我碰到的有三种会导致这种情况 1.当你的 S ...

  6. mysql从零开始之MySQL 教程

    MySQL 教程 MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数 ...

  7. 基于python深度学习的apk风险预测脚本

    基于python深度学习的apk风险预测脚本 为了有效判断安卓apk有无恶意操作,利用python脚本,通过解包apk文件,对其中xml文件进行特征提取,通过机器学习构建模型,预测位置的apk包是否有 ...

  8. 第29篇-调用Java主类的main()方法

    在第1篇中大概介绍过Java中主类方法main()的调用过程,这一篇介绍的详细一点,大概的调用过程如下图所示. 其中浅红色的函数由主线程执行,而另外的浅绿色部分由另外一个线程执行,这个线程最终也会负责 ...

  9. Java秘诀!零基础怎样快速学习Java?

    对于零基础想学Java的朋友,其实一开始最应该做的就是定好学习目标和端正学习态度,切记不要三天打鱼两天晒网! 首先你是零基础,现在急需把Java学好,在保证学习质量的同时,用最短的时间学好Java应该 ...

  10. 『Mivik的萌新赛 & Chino的比赛 2020』T2 题解 Galgame

    如果这是我最后一篇题解,请每年为我上坟. Galgame 题目传送门 Decription as_lky 搞到了很多 Galgame(真的很多!).一款 Galgame 可以被描述为很多场景(Scen ...