并发基础知识

写在前面的话

从这篇文章开始就正式进入了并发主题,该主题相关知识较前面的集合主题会比较晦涩难懂,需要不断回顾、整理,才能构建出自己的知识网络。

首先推荐一本讲并发的好书:JAVA并发编程实战。这本书非常完整的讲解了关于并发的知识点,是一本不可多得的好书,如果有时间一定要多看几遍。

下面放一张并发主题的思维导图(受限于网页大小,请童鞋们自行下载图片浏览):

从这张图中可以看到并发相关的知识点非常多并且非常杂,我们这个主题不可能把这里边所有罗列的知识点全部深入讲解一遍,所以我在这里只能挑选一些相对比较重要的知识点(大家可以认为是主干知识 : ))进行深入分析,至于剩下的一些枝枝叶叶就需要童鞋们自己去实践掌握啦。

OK,介绍就到这里,接下来正式开始知识点剖析,当然首先从基础知识开始(图中右下角线程部分)。

并发基础知识

这部分知识是相对来说比较简单并且容易理解的,我从这里开始写也是为了巩固童鞋们学习并发知识的信心,让大家能够更有动力的去学习。

1.什么是线程?什么是进程?它们之间有何联系?

关于这个问题,我准备用一个形象的例子来描述,这样比较容易理解:大家都有用过杀毒软件吧?当你打开杀毒软件,那么你就启动了一个进程。而现代的杀毒软件功能已不仅仅局限于查杀病毒了,比如还有清理垃圾文件、工具箱、修复漏洞、扫描驱动等等功能,而这一个个功能对应的其实就可以认为是一个个线程在执行任务(当然实际情况可能更复杂)。

从上面这个例子可以得出结论:进程是正在运行的程序的实例,而线程是程序中一个单一的顺序控制流程,它是程序执行流的最小单元。一个进程可以拥有许多个线程,这些线程可以共享该进程的全部资源,并且可以并发执行(比如你可以同时进行扫描病毒和修复漏洞的操作)。

2.如何创建并启动一个线程?

java中创建线程有两种方式:继承Thread基类 以及  实现Runnable接口。

继承Thread基类的方式:

1 class ExtendsThread extends Thread{
2
3     @Override
4     public void run() {
5        System.out.println("create thread by extends Thread class.........");
6     }
7 }

实现Runnable接口的方式:

1 class ImplementsThread implements Runnable{
2
3     @Override
4     public void run() {
5         System.out.println("create thread by implements Runnable interface.........");
6     }
7 }

创建线程后,就要启动线程去执行它的工作,两种创建线程方式有不同的启动方法:

 1 public class CreateThread {
 2
 3     public static void main(String[] args) {
 4         //使用 extends Thread 创建并启动线程
 5         ExtendsThread et = new ExtendsThread();
 6         et.start();
 7
 8         //使用 implements Runnable 创建并启动线程
 9         Thread runThread = new Thread(new ImplementsThread());
10         runThread.start();
11
12     }
13 }

这里有一个很古老的面试题:线程创建有哪两种方式?哪种方式比较好?为什么?

这个问题的答案要根据具体业务情况来回答,如果确实是非常非常简单的业务场景,我只需要一个线程就能完成任务,那么当然是implements Runnable接口的方式比extends Thread类的方式好。

因为大家知道java是单继承的,如果用extends的方式创建了线程,那么这个线程类就无法再继承别的类,而implements的方式则不会有这个问题,相对来说扩展性更好。

但是,现代的企业(尤其是互联网企业)中,基本不可能看到用这两种方式来创建线程的,而是使用Executors类提供的许多类型的线程池来创建并管理一组线程,为什么?

因为在复杂的、对性能和实时性要求非常高的业务场景下,用这两种创建线程的方式会造成大量资源的消耗,并且线程的上下文切换也会浪费大量的时间,所以java很贴心的为我们提供了线程池,以便于更好的管理许许多多的线程以适应业务需要。

这里再说一个额外的小知识点,大家有没有想过,如果我对同一个线程调用两次start()方法,会出现什么情况呢?

可以看到java会抛出异常:非正常的线程状态,在java中是不允许调用两次同一个线程的start方法的。

3.线程有哪几种状态?

既然上面提到了“非正常的线程状态”,那么接下来就讲一下java中线程的状态,其实共有6种:

1.NEW 新建状态。

顾名思义,在此状态下的线程就是刚刚创建出来的新线程。

2.RUNNABLE  可运行状态。

调用线程的start()方法并获取到资源锁(关于锁的知识后文会详细讲解)的线程就会进入此状态。注意,此时的线程可能正在虚拟机中执行任务,也有可能在等待CPU时间分片。

3.BLOCKED  阻塞状态。

某些代码可能会被加锁,而需要执行这些代码的线程首先需要获取到锁对象,如果线程因为没有获取到监视器锁而无法执行任务,则其就处于阻塞状态。

4.WAITING  等待状态。

如果线程执行了不带超时时间的wait方法或者join方法,那么线程就会让出执行权,并进入等待状态。

5.TIME_WAITING  超时等待状态

如果线程执行了带超时时间的wait方法或者join方法或者sleep方法,那么线程就会进入超时等待状态

6.TERMINATED  终止状态

无论是响应中断而强制结束的线程或者是正常执行任务完成后退出的线程都会处于这个状态。处于终止状态的线程不具备继续运行的能力。

线程的六种状态需要好好理解,这对于后面知识的理解会有一定帮助。

4.如何优雅的结束线程?

最后我们来讲一下如何优雅的结束一个线程。有的同学可能会说这还不简单,Thread相关api中不是有个stop方法嘛,只要调用这个方法线程不就结束了吗?

这里我先明确一下结论:stop方法确实有,但是这个方法具有不确定性,jdk1.5及以后这个方法已经被标示为“Deprecated(废弃)”状态,即不赞成在代码中继续使用该方法。

然而java中并没有提供能够立即使一个线程转变为TERMINATED状态的方法,取而代之的是提供了一种叫做“中断”的协调机制,可以使一个线程终止另一个线程当前的工作。

 1 /**
 2  * 优雅终止线程的方式
 3  */
 4 public class TerminateThread {
 5
 6     public static void main(String[] args){
 7         NeedStopThread nst = new NeedStopThread();
 8         try {
 9             nst.start();
10             Thread.sleep(3000);
11             nst.cancel();   //线程运行3秒后由主线程发出中断请求
12         } catch (Exception e) {
13             System.out.println("Exception in Main Thread.....");
14         }
15     }
16 }
17
18 class NeedStopThread extends Thread{
19
20     private AtomicInteger count = new AtomicInteger();
21
22     @Override
23     public void run() {
24         try {
25             while(!Thread.currentThread().isInterrupted()){   //当前线程未接收到中断信号
26                 System.out.println("i‘m running.........count now is " + count.getAndIncrement());
27             }
28         } catch (Exception e) {
29             System.out.println("Exception in NeedStop Thread.....");
30         }finally {
31             System.out.println("try to close io or sql resource here.........");
32         }
33     }
34
35     public void cancel(){
36         interrupt();  //由另一个线程调用发出中断信号,请求终止当前线程
37     }
38 }

大家可以多次执行这段代码,会发现结果肯定都是不一样的,这也证明了中断操作并不会让线程立即进入终止状态,最终进入终止状态的时间还是由当前线程自己判断的。

关于线程的基础知识讲解到这里就结束了。基础知识大家一定不能小看它,地基要扎稳,楼房才能盖的好。下篇文章就开始讲解线程间的通信和协作的几种方式,也是非常重要的内容。OK,我们下篇文章见。

原文地址:https://www.cnblogs.com/smartchen/p/9223948.html

时间: 2024-09-29 18:53:42

并发基础知识的相关文章

并发基础知识 — 线程安全性

前段时间看完了<并发编程的艺术>,总感觉自己对于并发缺少一些整体的认识.今天借助<Java并发编程实践>,从一些基本概念开始,重新整理一下自己学过并发编程.从并发基础开始,深入进去,系统学习一下并发编程. 编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问.对象的状态是指存储在状态变量(实例或静态域)中的数据.对象的状态还可能包括其他依赖对象的域.(Map.Entry) 一个对象是否需要时线程安全的,取决于该对象

【转】java 高并发 基础知识

锁: 内置锁 (监视器锁): 每个java对象都可以做一个实现同步的锁,这些锁被成为内置锁. 获得锁的唯一途径就是进入有这个锁保护的代码块或方法 重入锁: 由于内置锁是可重入的,因此如果某个线程试图获得一个以已经由他自己持有的锁, 那么这个请求就会成功.重入意味着获取锁的操作粒度是"线程",而不是"调用" volatile 使用条件(必须同时满足所有条件): 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值 该变量不会与其他状态变量一起纳入不

Java并发基础知识

1 线程和进程 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的.系统运行一个程序即是一个进程从创建,运行到消亡的过程. 在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程. 线程与进程相似,但线程是一个比进程更小的执行单位.一个进程在其执行的过程中可以产生多个线程.与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器.虚拟机栈和本地方法栈,所以系统在

互联网开发(一) 并发基础知识

一.并发的基本含义        在操作系统中,并发是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行. 在关系数据库中,允许多个用户同时访问和更改共享数据的进程.SQL Server 使用锁定以允许多个用户同时访问和更改共享数据而彼此之间不发生冲突. 在网络服务器上,并发是指同一时刻能处理的连接数,可以理解为服务器最多维护多少个会话数,比如,服务器能建立1000个TCP连接,即服务器同时维护了1000个so

Java并发(基础知识)—— Executor框架及线程池

在Java并发(基础知识)—— 创建.运行以及停止一个线程中讲解了两种创建线程的方式:直接继承Thread类以及实现Runnable接口并赋给Thread,这两种创建线程的方式在线程比较少的时候是没有问题的,但是当需要创建大量线程时就会出现问题,因为这种使用方法把线程创建语句随意地散落在代码中,无法统一管理线程,我们将无法管理创建线程的数量,而过量的线程创建将直接使系统崩溃. 从高内聚角度讲,我们应该创建一个统一的创建以及运行接口,为我们管理这些线程,这个统一的创建与运行接口就是JDK 5的Ex

Android 并发编程:(一)基础知识 —— 架构和组件

本章节所有内容皆为原创,如需转载,请注明出处. http://blog.csdn.net/manoel/article/details/38462631 写在前面的话 很久没写博客了,一是因为自身水平有限,怕误人子弟:二是因为感觉没什么可写的:三是因为时间有限,要寻找工作.学习和生活之间的平衡. 最近一直在研究和梳理Android多线程编程的东西,希望能够把这些分享给大家. 想必做过Android应用开发的同学应该都会知道,多线程是一个特别"诡异"的地方.之所以称为"诡异&q

Android 并发编程:(一)基础知识 —— 1.2 程序的启动和终结

本章节所有内容皆为原创,如需转载,请注明出处. http://blog.csdn.net/manoel/article/details/38471825 Android是一个多用户,多任务的系统. 允许多个app在同一时刻执行,在多个程序之间切换并不会有明显的延迟. 多任务是由Linux内核负责处理的,而程序的运行基于Linux进程. Linux进程 Linux为每一个用户分配一个唯一的用户ID(User ID),用于区分不同的User. 因为权限的原因,每一个用户只能访问私有资源,没有用户(除

PHP面试(二):程序设计、框架基础知识、算法与数据结构、高并发解决方案类

一.程序设计 1.设计功能系统--数据表设计.数据表创建语句.连接数据库的方式.编码能力 二.框架基础知识 1.MVC框架基本原理--原理.常见框架.单一入口的工作原理.模板引擎的理解 2.常见框架的特性--PHP框架的差异和优缺点 三.算法与数据结构 1.常见算法--算法的概念.时间复杂度和空间复杂度.常见排序算法.常见查找算法 2. 3. 4. 四.高并发解决方案 1. 2. 原文地址:https://www.cnblogs.com/darklights/p/9275751.html

【MySQL优化】MySQL 高并发配置优化基础知识

[MySQL优化]MySQL 高并发配置优化基础知识 MySQL的优化分为两个部分,一是服务器物理硬件的优化,二是MySQL自身(my.cnf)的优化. 一.服务器硬件对MySQL性能的影响 ① 磁盘寻道能力(磁盘I/O),以目前高转速SCSI硬盘(7200转/秒)为例,这种硬盘理论上每秒寻道7200次,这是物理特性决定的,没有办法改变. MySQL每秒钟都在进行大量.复杂的查询操作,对磁盘的读写量可想而知.所以,通常认为磁盘I/O是制约MySQL性能的最大因素之一,对于日均访问量 在100万P