Java高并发入门详细讲解

上期回顾及问题总结

上次说了创建线程的两种常用方式,第三种方式在后面的更新中会讲解到。这里对于上一节的内容做个回顾。

  1. 在上一节中说到了创建多线程的问题,分析了Thread的源码,提出了三种的线程实现的方式。
  2. 简单的分析了共享资源锁竞争的问题,同样也引出了锁竞争的问题。
    这次我们就来结合实践详细的说说关于创建线程的其他的注意点。

入门例子

首先你是一个非常爱音乐的人,在平时你也喜欢听歌。如果你想在看新闻的时候也想听歌,这样的话让我们用Java代码来实现一下。

public class TryConcurrency {public static void main(String[] args) {browsNews();enjoyMusic();}/*** 听音乐*/private static void enjoyMusic() {for (;;){System.out.println("this is good Music");sleep(1);}}/*** 看新闻*/private static void browsNews() {for (; ; ) {System.out.println("this is good News");sleep(1);}}private static void sleep(int i) {try {TimeUnit.SECONDS.sleep(i);} catch (InterruptedException e) {e.printStackTrace();}}
}

this is good News
this is good News
this is good News
this is good News
this is good News
this is good News

以上是我们输出的结果,看样子并不是我们想要的结果,并没有实现一遍听歌一边看新闻的功能。这里我们将以上的代码做一个优化,当然这里使用的Java8编程。如果对Java8不是很熟悉的人可以熟悉一下Java8的新特性。
如果我们想实现一边听歌一边看新闻的话就要做如下的改变

public static void main(String[] args) {new Thread(()->{enjoyMusic();}).start();browsNews();}

使用我们上节课说过的多线程的知识来解决这个问题。

This is good Music
this is good News
this is good News
this is good Music
this is good News
this is good Music
this is good News

生命周期分析

这样我们就会看到如上的结果,在一边听歌的同时一边看看新闻。既然引入了多线程的概念,那么我们就来看看多线程的生命周期有哪些,从上节课的分析中我们可以知道,在使用多线程的时候,需要调用start方法

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();/* Notify the group that this thread is about to be started* so that it can be added to the group's list of threads* and the group's unstarted count can be decremented. */group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}
}

生命周期调用关系图

在调用了start方法之后又会发生什么样的变化,那么我们就来看看线程的生命周期

关系说明

这张图是从一本书上截图的,从图中可以看到线程的五种状态,首先是new,也就是实例化一个线程,通过start方法的调用进入到了Runnable状态,当然在这个状态值能保证它是可是执行的,也就是说当它拿到资源之后立即可以执行,Running状态,在这个状态中表示线程在实现,通过调用yield,表示谦让的意思。将资源让出来之后原本处于Runnable状态的线程就会有获取到资源进入到Running状态,如果在Runnable状态或者在Running状态的线程调用了sleep方法或者是wait方法就会进入到Blocked(阻塞)状态,进入阻塞状态的线程有两种结果,一种是资源不够用了直接stop,另一种是通过调用notify或者notifyAll方法唤醒执行。而正常执行结束的线程或者是被Stop的线程就会进入到Terminated状态(最终状态)在这个状态的线程将不会被切换到任何的状态,这也意味着线程的整个生命周期的结束。而以下的情况将会导致线程进入到最终状态,其实在之前也提到了

  1. 线程正常运行结束生命周期
  2. 线程出现意外
  3. JVM Crash导致所有的线程都结束

上面我们提到了Start方法源码,这里我们分析完线程的生命周期之后再次的进入到start源码中,其实在start源码中做的最主要的一件事情就是调用我们start0方法,这个方法是JNI方法,也就是在Java编程中调用底层C语言或者C++语言的代码。当我们执行start方法的时候就会执行run方法,从而执行strat0方法。而在上一节中我们提到了Thread的源码

Thread源码实例分析

首先Thread被构造后的new状态,这个是时候threadStatus这个内部属性为0,如果两次启动Thread,就会出现IllegalThreadStateException异常,线程启动之后就被加入到一个ThreadGroup线程组中,当一个线程结束,也就是到了Treminated状态,再次调用start方法是不允许的。也就是说了Treminated状态是没有办法会到Runnable/Running状态的。这个逻辑我们使用代码来模拟一下

第一种情况

@Test
public void testMain(){Thread thread = new Thread(){@Overridepublic void run() {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}};thread.start();thread.start();
}

第二种情况

@Test
public void testMain1() throws InterruptedException {Thread thread =new Thread(){@Overridepublic void run() {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}};thread.start();TimeUnit.SECONDS.sleep(3);thread.start();
}

总结

以上两段代码都会引起IllegalThreadStateException异常,但是两个异常抛出却是有着本质的区别,第一个是重复启动,只是第二次启动不允许,但是此时线程属于运行状态,第二次企图重新激活也抛出了非法状态的异常,此时没有线程,因为该线程的生命周期已经被终结。到这里我们就看到了整个线程的生命周期

Java高并发入门-线程初步(二)相关推荐

  1. Java高并发入门-线程初步

    Java高并发入门-线程初步 线程与进程之间的关系 进程就是我们运行在计算机上的一个程序,对应Java程序来说就是运行在计算机上的Java应用程序,这个程序在运行的时候就会创建了一个进程,服务器上就会 ...

  2. java queue 线程安全_详解Java高并发——设计线程安全的类

    前言: 将现有的线程安全的组件组合为更大规模的组件或程序. 通过使用封装技术可以使得在不对整个程序进行分析的情况下就可以判断一个类是否是线程安全的. 一. 基本要素 1. 找出对象状态的所有变量 如果 ...

  3. Java高并发编程(十二):Executor框架

    Java中的线程既是工作单元,也是执行单元.工作单元包括Runnable和Callable,而执行单元是由Executor框架支持. 1. Executor框架简介 ExecutorsService的 ...

  4. Java高并发编程学习(三)java.util.concurrent包

    简介 我们已经学习了形成Java并发程序设计基础的底层构建块,但对于实际编程来说,应该尽可能远离底层结构.使用由并发处理的专业人士实现的较高层次的结构要方便得多.要安全得多.例如,对于许多线程问题,可 ...

  5. Java高并发编程详解系列-Java线程入门

    根据自己学的知识加上从各个网站上收集的资料分享一下关于java高并发编程的知识点.对于代码示例会以Maven工程的形式分享到个人的GitHub上面.   首先介绍一下这个系列的东西是什么,这个系列自己 ...

  6. Java高并发程序设计入门

    转自:http://blog.csdn.net/johnstrive/article/details/50667557 说在前面 本文绝大部分参考<JAVA高并发程序设计>,类似读书笔记和 ...

  7. SpringBoot实现Java高并发秒杀系统之Service层开发(二)

    继上一篇文章:SpringBoot实现Java高并发秒杀系统之DAO层开发 我们创建了SpringBoot项目并熟悉了秒杀系统的表设计,下面我们将讲解一下秒杀系统的核心部分:Service业务层的开发 ...

  8. [Java高并发系列(5)][详细]Java中线程池(1)--基本概念介绍

    1 Java中线程池概述 1.1 什么是线程池? 在一个应用当中, 我们往往需要多次使用线程, 这意味着我们需要多次创建和销毁线程.那么为什么不提供一个机制或概念来管理这些线程呢? 该创建的时候创建, ...

  9. Java高并发程序设计(三)——JDK并发包(二)

    引言 好久没来学习Java高并发程序设计了,感觉在慢慢遗忘之前学过的内容,今天打算重新拾起. Condition Condition与前两章讲的Object.wait() 和Object.notify ...

最新文章

  1. ISAPI_Rewrite3.1相关知识
  2. 《我在51CTO微职位学软考——奋发之路》
  3. 如何黑掉一台根本不联网的电脑
  4. Android之自定义AlertDialog的实现方法(一)
  5. HTML Img Compression(压缩)
  6. System.getProperty(user.dir) 获取jar包所在目录
  7. 湖北文理学院数学与计算机科学学院,数学与计算机科学学院计算机协会十一月总结会议...
  8. [解题报告]Codeforces 105D Entertaining Geodetics
  9. 手机按三角返回页面上一页_小猿圈微信小程序跳转页面都有哪些?
  10. UIDatePicker 显示时间和打印时间不一样
  11. 每天10个Linux命令四
  12. [Micropython]TPYBoard开发板点亮心形8*8点阵
  13. kingroot android 8.1,360一键root手机版
  14. 学妹面试拼刀刀被问Java策略模式是什么鬼?哈哈哈哈
  15. spark大数据的学习
  16. jsp 页面进行debug 断点找错误
  17. 1700人参加的钢铁行业盛会,下面是你必须知道的!
  18. 检测网络连接是否正常的方法
  19. ios wifi 定位_iOS最新跳转手机设置WIFI定位等界面方法适配iOS11
  20. 离散数学 学习笔记-Day4

热门文章

  1. loggerFactory java_java日志LoggerFactory.getLogger最全讲解使用方法
  2. ssh oracle id native,hibernate解决oracle的id自增?
  3. Scala 中的集合(三):实现一个新的 Collection 类
  4. 纷享逍客宣布完成E+轮融资 长山兴资本领投
  5. jQuery 属性操作 - toggleClass() 方法
  6. Log4j.xml配置日志按级别过滤并将指定级别的日志发送到ActiveMQ
  7. 让redhat5以yum方式安装软件
  8. Mysql批量更新的一个坑-allowMultiQueries=true允许批量更新
  9. 常用的几个PHP加密函数
  10. 2018.6.5今天跟着视频做了一个提交Todolist