Java增强之并发编程

1 多线程

1.1 进程及线程

程序启动的时候,电脑会把这个程序加载到内存,在内存中需要给当前的程序分配一段的独立运行的空间,这个空间就专门负责这个程序的运行。每个应用程序运行都需要在内存中有自己独立的运行空间,互不影响。进程就是应用程序在内存中的独立空间,负责当前应用程序的运行,负责调度当前程序中的所有运行细节。

线程:位于进程中,负责当前进程中的某个具备独立运行资质的空间,负责程序中具体的某个独功能的运行。一个进程中至少有一个线程,可以并发运行多个线程。多线程之间共享同一个堆空间,每个线程都有自己独立的栈空间

1.2 多线程

在一个进程中,同时开启多个线程,同时去完成某些任务。

一个进程可以并发运行多个线程,提高运行效率。

1.3 多线程运行的原理

CPU在线程中做时间片的切换。程序的运行时CPU负责的,其实CPU在运行程序时,某个时刻只能运行一个程序,CPU在多个程序之间进行高速的切换,因为切换的频率和速度太快了,所以我们是看不出来的。从而得知多线程虽然可以提高程序的运行效率,但是不能无限制的开线程。

1.4 实现线程的方式

(1)继承Thread类

(2)实现Runnable接口

(3)Callable和FutureTask创建线程

(4)通过线程池创建线程

代码演示见之前的文章:https://blog.csdn.net/weixin_43786255/article/details/92065717

1.5 线程状态图解

详细讲解见:https://blog.csdn.net/weixin_43786255/article/details/92065717

2 java同步关键字

在多线程编程中,为了达到线程安全的目的,往往通过加锁的方式来实现。

2.1 synchronized

是JVM级别的锁,在编译过程中,在指令级别加入一些标识来实现。无法中断正在阻塞队列或者等待队列的线程。synchronize是java语言的内置特性,锁的释放是由jvm决定的,人工无法干预 。

常与wait(),notify(),notifyAll()方法联用,调用wait()方法线程让出CPU,释放锁,进入等待状态waitting,进入等待队列。当其他线程调用notify()(随机唤醒等待队列中的一个线程)或notifyAll()(唤醒等待队列中的全部线程)时没会将队列中的线程对象,放入第二个阻塞队列,状态是blocked,等待锁被释放后,开始竞争锁。

synchronize提供了偏向锁,轻量级锁,重量级锁。

锁的释放时机有两种情况:

①获取锁的线程操作完成,该线程会自动释放锁 ;②)获取锁的线程出现异常,jvm会自动释放。

synchronized存在的问题 :

①如果获取锁标记的线程不主动释放锁,则未获取标记的只能等待,而且人工无法干预;②当多个线程读写文件时,读读操作互相不影响,但是synchronized仍然无法同时执行。

2.2 Lock

Lock锁是Java代码级别的,用户可以主动添加锁,但是必须手动释放锁。因此一般来说,使用 Lock 必须在 try{}catch{}块中进行,并且将释放锁的操作放在 finally 块中进行,以保证锁一定被被释放,防止死锁的发生。提供了公平锁,轮询锁,定时锁,可中断锁等,还增加了多路通知机制(Condition),可以用一个锁来管理多个同步块。

与synchronized的区别:

①synchronized 是 Java 语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

②synchronized 由系统自动释放,lock必须手动释放,否则可能产生死锁。

常见方法如下:

void lock() 获取锁(阻塞,如果其他线程获取到锁,需要等待)
boolean tryLock() 获取锁(非阻塞,如果其他线程获取到锁,则返回false)
boolean tryLock(long time, TimeUnit unit) 获取锁(在指定的时间范围内获取,超时返回false)
void lockInterruptibly() 可中断锁
void unlock() 释放锁

ReentrantLock 类是唯一实现了Lock 接口的类,并且 ReentrantLock 提供了更多的方法。

区别对待读、写的操作用ReadWriteLock接口的实现类ReentrantReadWriteLock 里面提供了很多丰富的方法,不过最主要的有两个方法:readLock()和 writeLock()用来获取读锁和写锁。

ReadWriteLock将读写操作分离处理:

①一个线程获取读锁,另外的线程可以获取读锁。但是不能获取写锁(必须等待读锁释放)。

②一个线程获取写锁,那么一定要等待该线程释放写锁,其他线程才能执行读写操作。

2.3 死锁

死锁:两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,会让程序挂起无法完成任务。

产生死锁的条件:

①互斥条件:一个资源每次只能被一个进程使用;

②请求与保持条件:一个进程因请求资源而阻塞式,对已获得的资源保持不放;

③不剥夺条件:进程已获得的资源,在未使用完成之前,不能强制剥夺;

④循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何避免死锁:避免相互等待,设置标记位

死锁处理:破坏条件

2.4 Volatile特殊域变量

首先了解在多线程编程中,要解决的问题主要有以下三方面:

①原子性:作为一个整体运行

②可见性:多个线程修改的内容是可见的。CPU不是直接和系统内存通信,而是把变量读到内部的缓冲,也叫私               有的数据工作栈,修改也是在内部缓存中,但是何时修改到系统内存不能确定,这个时间差就可能导致读到的值不是最新             值。

③指令重排:虚拟机把代码编译成指令后,出于优化,保证代码不变的情况下,会调整指令的执行顺序

valotile能够满足可见性和有序性,但无法保证原子性。

①保证可见性:在修改后强行把对变量的修改同步到系统内存中,当其他CPu在读取自己内部缓存中的值发现是                volatile修饰的时候会把内部缓存中的值置为无效,从系统内存中读取。

②保证有序性:在某些指令中插入屏障指令,用于确保在向屏障指令后面继续执行的时候,前面的所有指令已经                输入完毕。

原子性通过原子量:Atomicxxx:原子量保证数据的原子性

2.5 ThreadLocal线程变量副本

ThreadLocal提供了线程本地变量,访问本地变量的每个线程都会拷贝一个变量到自己的本地内存,多个线程操作这个变量的时候,实际上是操作自己本地内存里面的变量,这样就不会对其他线程产生影响。

ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题,ThreadLocal采用以时间换空间的方式,同步机制采用以空间换时间的方式

作用:保证线程的独立变量。

应用场景:有变量或对象实例需要在线程中多个地方被重复使用,不希望线程之间共享,又不希望每次使用是都重新创建,加大内存开销。

与Synchronized的区别:Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

使用:可以将可以将 ThreadLoad<T>视为 Map<Thread ,T>,把需要隔离的数据放入ThreadLocal,通过threadLocal.set(val)赋值,threadLocal.get()获取值,最好不要放在线程池中,避免复用。

3 并发包

3.1 java并发包

jdk1.5版本以后,大多数的特性在 java.util.concurrent 包中,是专门用于多线程发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发应用程序。主要包含原子量、并发集合、同步器、可重入锁,并对线程池的构造提供了强力
的支持。

3.2 线程池

通过重用现有的线程池,而不是创建新的线程,可以在处理多个请求的时候分摊在线程创建和销毁过程中产生的巨大开销,当请求到达的时候工作线程已经存在,不会由于等待创建线程而延迟执行,从而提高系统的响应性。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

corePoolSize: 核心池的大小(常驻线程数)
maximumPoolSize: 最大的线程数(任务数)
keepAliveTime: 线程空闲的等待时间
unit:等待时间的单位
workQueue: 并发的等待队列(如果任务数超过核心池的大小,任务需要在队列中等待,有界/无界)
factory: 线程工厂,创建线程
handler: 任务拒绝的策略(队列中的任务数和核心池的任务数超过总的max/任务数超过核心池+有界队列中的数目)

ThreadPoolExecutor的执行顺序:

①当线程数小于核心线程数时,创建线程

②当线程数大于核心线程数,且队列未满时,将任务放入任务队列

③当线程数大于核心线程数时,且队列任务已满,若线程数小于最大线程数(核心线程数+有界队列的数目),则创建线程;若线程数大于最大线程数,则抛出异常,拒绝任务。

更多详细讲解见:https://blog.csdn.net/weixin_43786255/article/details/92065717

Java增强之并发编程相关推荐

  1. Java 多线程与并发编程专题

    Java 线程基础 Java 多线程开发 线程安全与同步 并发控制 非阻塞套接字(NIO) Java 5 中的并发 JDK 7 中的 Fork/Join 模式 相关书评 Java 平台提供了一套广泛而 ...

  2. 《Java线程与并发编程实践》—— 2.3 谨防活跃性问题

    本节书摘来异步社区<Java线程与并发编程实践>一书中的第2章,第2.3节,作者: [美]Jeff Friesen,更多章节内容可以访问云栖社区"异步社区"公众号查看. ...

  3. Java零基础并发编程入门

    Java零基础并发编程入门 并发编程主要包括: 线程,同步,future,锁,fork/join, volatile,信号量,cas(原子性,可见性,顺序一致性),临界性,分布式 了解基础: JMM: ...

  4. java书籍_还搞不定Java多线程和并发编程面试题?你可能需要这一份书单!

    点击蓝色"程序员书单"关注我哟 加个"星标",每天带你读好书! ​ 在介绍本书单之前,我想先问一下各位读者,你们之前对于Java并发编程的了解有多少呢.经过了1 ...

  5. 《Java线程与并发编程实践》—— 2.6 小结

    本节书摘来异步社区<Java线程与并发编程实践>一书中的第2章,第2.6节,作者: [美]Jeff Friesen,更多章节内容可以访问云栖社区"异步社区"公众号查看. ...

  6. 《Java线程与并发编程实践》—— 1.2 操作更高级的线程任务

    本节书摘来异步社区<Java线程与并发编程实践>一书中的第1章,第1.2节,作者: [美]Jeff Friesen,更多章节内容可以访问云栖社区"异步社区"公众号查看. ...

  7. 厚积薄发打卡Day26:狂神说Java之JUC并发编程<代码+笔记>(上)

    前言: 学习视频来源:[狂神说Java]JUC并发编程最新版通俗易懂 一个十分优秀且励志的技术大牛+Java讲师,十分推荐他的频道:遇见狂神说

  8. Java多线程与并发编程终极宝典

    阅读本文需要了解的概念 原语 所谓原语,一般是指由若干条指令组成的程序段,用来实现某个特定功能,在执行过程中不可被中断.在操作系统中,某些被进程调用的操作,如队列操作.对信号量的操作.检查启动外设操作 ...

  9. 基于《狂神说Java》JUC并发编程--学习笔记

    前言: 本笔记仅做学习与复习使用,不存在刻意抄袭. -------------------------------------------------------------------------- ...

最新文章

  1. python输入输出有问题_python – Modbus错误:[输入/输出]无从远程...
  2. 祝贺自己itpub和csdn双双荣获专家博客标题
  3. 【专题】“莓日一介”之(BlackBerry 7230“经典”)
  4. 读取复杂结构的yml配置项
  5. 【Android Gradle 插件】ProductFlavor 配置 ( ProductFlavor#manifestPlaceholders 清单文件占位符配置 )
  6. 浸会大学计算机专业硕士排名2019,2019软科世界大学学术排名香港浸会大学排名第701-800...
  7. opencv 在debian6.0下安装
  8. Shell 判断数是否为某数的倍数
  9. 如何解决常见的 Active Directory 复制错误
  10. 一片关于Bootstarp4的文章
  11. shell php的守护进程,实例详解shell编写守护进程的方法
  12. 【MS SQL Server】SQL Server2005下载地址
  13. 【GD32F303开发之串口通信】
  14. zencart模板制作步骤详解
  15. 计算机打字训练教学教案,打字练习小游戏教案.doc
  16. 解决word2019中求和符号上下标被强制挪到右边的问题
  17. 如何将PlayStation 4恢复出厂设置
  18. 字符串函数---atoi()函数详解及实现(完整版)
  19. Elasticsearch 学习(二).实战使用
  20. JavaOOP面试题(108道)

热门文章

  1. 面试题25:合并两个排序的链表
  2. TZOJ--1518: 星星点点 (二进制模拟)
  3. 《你的灯亮着吗》阅读笔记(三)
  4. 任务并行VS数据并行
  5. Workflow WF Reference Links for 2009-03-20
  6. C++排序之stable_sort()的方法
  7. 1024对话内核大神谢宝友
  8. 学习,一定是脱“贫”致富的捷径
  9. 什么集成mysql_mysql集成部署
  10. 无忧计算机二级试题题库,全国计算机二级MS Office试题