Java并发是比较难的知识点,难于对并发的理解。并发要从操作系统和硬件层面去理解,才会比较深入,而不单单是从编程语言的逻辑去理解。

首先对于并发要清楚的几点:

线程可能在任何时刻被切换。
计算机只对硬件指令保证原子性。
CPU有多级缓存,每个线程有自己的缓存空间。

第一点:

如果有共享数据或多线程判断逻辑,需要使用锁机制互斥其他线程的访问,避免逻辑错误。

第二点:

例如下面这个语句在编程语言里面只有一条语句,但编译成汇编语言会有三条硬件指令:(1)load i变量,(2)i变量自增1 (3)保存自增后的i变量。因此下面的语句不具有原子性。
i++;
第三点:
造成变量的可见性问题,单个线程读取并修改,修改的是自己线程缓存里面变量,对其他线程不可见,会造成可见性问题。

Java解决并发问题的一些关键字
1.synchronized关键字
监视器模式的锁,可以使代码块在线程之间互斥,持有锁的线程可以运行,没有持有锁的线程进入阻塞队列等待。synchronized是可重入锁,持有锁的线程可多次进入代码块。synchronized关键字修饰的代码块/方法内的代码具有原子性、可见性,可以解决上面的1、2、3问题。
2.volatile关键字
修饰变量,保证了变量的可见性,修饰的变量不再被CPU缓存,每次读取从内存中读取。每次写入变量也会立即刷新到内存,以保证变量对其他线程可见。还可以避免指令重排序,以及避免字分裂( 64位变量指令操作的分为两步)。但是这个不保证原子性。可解决上面的问题3。
3.final关键字
保证变量的不变性,如果一个变量是不变的,那么这个变量一定是线程安全的。
需要注意的是JVM为了性能优化,会对编译后的指令进行重排序,即在单个线程内是无影响的,但是对于多个线程来看重排序可能会导致预期之外的错误。volatile可以避免指令重排序。
在Java中的多线程是一一映射到操作系统的内核线程,每次线程切换都要经过内核态,对性能影响较大。
在Java中线程对应是的Thread类

Thread类通过接收一个Runnable接口的run方法来确定线程的执行逻辑。

Thread类通过start()方法来启动线程,里面执行的是定义好的run方法,start()方法只能执行一次,否则会报IllegalThreadStateException。

Thread thread = new Thread(() -> {
System.out.println(“hello world”);
});
thread.start();
Runnable接口是一个函数式接口,可以使用lambda表达式。

Thread类的其他方法介绍

1.sleep()方法

让目前正在执行的线程休眠,让CPU去执行其他的任务。

2.join()方法

线程合并,即当前线程会阻塞调用join()的线程,直到join的线程执行完成或超出设定的等待时间。

3.yield()方法

线程的yield(让步)操作的作用是让目前正在执行的线程放弃当前的执行,让出CPU的执行权限,使得CPU去执行其他的线程。

线程的状态

1.NEW状态

​new Thread()创建了线程,但未调用start()启动线程。

2.RUNNABLE状态

Java把Ready(就绪)和Running(执行)两种状态合并为一种状态:RUNNABLE(可执行)状态(或者可运行状态)。调用了线程的start()实例方法后,线程就处于就绪状态。此线程获取到CPU时间片后,开始执行run()方法中的业务代码,线程处于执行状态。

3.BLOCKED状态处于BLOCKED(阻塞)状态的线程并不会占用CPU资源,以下情况会让线程进入阻塞状态:

(1)线程等待获取锁

(2)IO阻塞

4.WAITING状态

处于WAITING(无限期等待)状态的线程不会被分配CPU时间片,需要被其他线程显式地唤醒,才会进入就绪状态。

Object.wait()方法,对应的唤醒方式为:Object.notify()/Object.notifyAll()。

Thread.join()方法,对应的唤醒方式为:被合入的线程执行完毕。LockSupport.park()方法,对应的唤醒方式为:LockSupport.unpark(Thread)。

5.TIMED_WAITING状态
处于TIMED_WAITING(限时等待)状态的线程不会被分配CPU时间片,如果指定时间之内没有被唤醒,限时等待的线程会被系统自动唤醒,进入就绪状态。
6.TERMINATED状态线程结束任务之后,将会正常进入TERMINATED(死亡)状态;或者说在线程执行过程中发生了异常(而没有被处理),也会导致线程进入死亡状态。

公众号:

推荐阅读:
《Java并发编程实践》

最新文章

  1. TCP的三次握手(建立连接)和四次挥手(关闭连接)
  2. nginx中的超时设置
  3. Python的SublimeText开发环境配置
  4. C++与C的关系
  5. Linux新手应掌握的10个基本命令
  6. Python 前端之JS
  7. Android框架
  8. Android读取RAM,ROM,SD卡容量
  9. 学习Slim Framework for PHP v3 (七)--route middleware怎么被add进来的?
  10. iOS IAP教程
  11. Javascript校验含中文的字符串长度
  12. Docker 生成Node.js web app(含端口映射)
  13. --@angularJS--路由插件UI-Router
  14. 7.Flask文件上传
  15. VIM 编辑器
  16. python--第十四天总结(js)
  17. linux+vs2013编译静态库和动态库
  18. Confluence 6 自定义空间布局
  19. JIRA Rest JAVA Client API实现问题管理及自定义字段(原创)
  20. OA项目实战学习(7)——初始化数据&权限配置显示

热门文章

  1. Windows常用快捷键及基本的Dos命令
  2. 备份 MySQL 的 shell 脚本(mysqldump版本) shell脚本
  3. Java 8 Stream API 引入和使用
  4. 抓包分析 TCP 握手和挥手
  5. 想开发DAYU200,我教你
  6. 【深入浅出 Yarn 架构与实现】2-1 Yarn 基础库概述
  7. windows socket网络编程--事件选择模型
  8. C#多线程之同步基础篇
  9. Json web token(JWT)攻防
  10. hwlog--utils.go