栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > Java

Java并发编程(线程)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java并发编程(线程)

文章目录
  • 何为进程和线程
    • 程序计数器为什么是私有的?
    • 虚拟机栈和本地方法栈为什么是私有的?
  • 堆和方法区
  • 并发与并行的区别?
  • 线程的生命周期和状态?
  • 什么是线程死锁?
  • 产生死锁的四个必要条件
  • 如何预防和避免死锁?
  • 说说 sleep() 方法和 wait() 方法区别和共同点?
  • 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
  • synchronized 和 volatile 的区别?
  • synchronized 和 ReentrantLock 的区别
  • 请你说一下自己对于 AQS 原理的理解
  • 并发编程的重要特性

何为进程和线程


进程:
进程是程序的运行的基本单位,系统运行一个程序就是从一个进程开始创建的。java中main方法的启动,就是启动了一个进程。
线程:
线程是比进程更小的执行单位。
一个进程中可以包括多个线程。

二者的区别:【从图中可以看出】

  1. 进程中可以包含多个线程。
  2. 多个线程之间共享堆和方法区
  3. 每个线程有自己的虚拟机栈、本地方法栈、程序计数器
程序计数器为什么是私有的?

程序计数器私有主要是为了线程切换后能恢复到正确的执行位置

虚拟机栈和本地方法栈为什么是私有的?

为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。

堆和方法区

堆:是进程中最大的一块内存,用于存放新创建的对象
方法区:用于存放已被加载的类信息、常量、静态变量、代码等。

并发与并行的区别?

并发:两个及其以上的作业在同一时间段内执行。
并行:两个及其以上的作业在同一时刻执行。

线程的生命周期和状态?



生命周期:
首先,创建线程的时候,处于NEW状态。
然后,调用start()方法后,称为,runnable状态
最后,当线程执行完run()方法之后,称为terminated终止状态
其中,当线程执行到wait()方法的时候,线程会进入等待状态,需要其他线程执行通知notify()操作,才可以返回到正常运行状态。
当线程通过sleep()方法可以将线程处于超时等待状态。等到超时时间到达后,自动回归正常运行状态。
当线程调用同步方法的时候,没有获得锁的情况下,线程会进入到blocked阻塞状态

什么是线程死锁?

死锁:
多个线程同时阻塞,它们都在相互等待资源的释放,由于线程被无限期阻塞,因此程序不可能正常终止,称为死锁

如果所示,线程A持有资源2,线程B持有资源1,它们都申请访问对方的资源,由于都不进行释放,因此进入死锁状态。

产生死锁的四个必要条件
  1. 互斥条件:资源只由一个线程占用
  2. 请求与保持条件: 一个线程因为请求资源而阻塞的时候,对自己已经获得到资源不进行释放
  3. 不剥夺条件: 线程已经获得到资源在没有使用完之前不能被其他线程剥夺,只有自己用完了之后才进行释放。
  4. 循环等待条件: 多个线程之间形成了头尾相连的循环等待状态。eg:圆桌池饭筷子问题
如何预防和避免死锁?

预防的话,只需要破坏产生死锁的条件之一就可以。
破坏其中条件:
第一个,互斥条件是无法被打破的,因此线程安全就是以互斥的条件保证的。
第二个请求与保持,一次性申请所有的资源
第三个不可剥夺,占用一部分资源的线程进一步申请其他资源,如果申请不到的话,就主动释放它占有的资源
第四个循环等待,只需要按照顺序申请资源,按照某一个顺序申请资源就可以避免循环等待条件。

说说 sleep() 方法和 wait() 方法区别和共同点?

共同点:
它们都可以暂停线程的运行
区别:
sleep方法没有释放锁,而wait方法释放了锁
wait方法被调用的时候,线程不会自然苏醒,需要别的线程执行notify唤醒。
而sleep方法被调用的时候,超过了所设定的时间段,线程会自动苏醒。

为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?

new 一个 Thread,线程进入了新建状态。
调用 start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。
start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。
但是,直接执行 run() 方法,会把 run() 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
总结: 调用 start() 方法方可启动线程并使线程进入就绪状态,直接执行 run() 方法的话不会以多线程的方式执行。

synchronized 和 volatile 的区别?
  1. volatile关键字是线程同步的轻量级实现方法,volatile只能用于变量,而synchronized用于修饰方法和代码块
  2. volatile关键字可以保证数据的可见性,而不能保证原子性。但是synchronized可以都保证
  3. volatile关键字用于解决多个线程之间的可见性,synchronized关键字解决多个线程之间访问资源的同步性。
synchronized 和 ReentrantLock 的区别

主要有以下几点:

  1. 用法不同,synchronized可以用于修饰方法和代码块,而reentrantlock只能用于修饰代码块
  2. 获取锁和释放锁的方式不同,synchronized会自动的加锁和释放锁。进入synchronized的时候会自动加锁,离开其修饰的代码段的时候会自动释放锁,但是reentrantlock需要手动加锁,通过lock()方法和unlock()加锁和释放

  3. 锁类型不同,synchronized锁为非公平锁,也就是(都等待加锁的时候,进行抢占式加锁)而reentrantlock可以是公平锁也可以是非公平锁
请你说一下自己对于 AQS 原理的理解

AQS 的全称为(AbstractQueuedSynchronizer)
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出大量应用广泛的同步器,比如我们提到的 ReentrantLock,Semaphore,其他的诸如 ReentrantReadWriteLock,SynchronousQueue,FutureTask 等等皆是基于 AQS 的。

AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列(虚拟的双向队列)锁实现的,即将暂时获取不到锁的线程加入到队列中。

并发编程的重要特性
  1. 原子性: 一次或者多次操作的时候,要么全部执行,要么都不执行,不会受到干扰打断。
    可以通过synchronized锁实现原子性
  2. 可见性: 当一个线程对共享变量进行修改的时候,另外的线程都是可以立即看到修改的最新内容。
    可以通过synchronized锁/volatile锁实现可见性
  3. 有序性: 由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。
    我们上面讲重排序的时候也提到过:
    指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致 ,所以在多线程下,指令重排序可能会导致一些问题。
    在 Java 中,volatile 关键字可以禁止指令进行重排序优化。
转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1039706.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号