2020-10-14初入多线程

2020-10-14初入多线程,第1张

2020-10-14 初入多线程

个人认为的经典文章:

[http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html](http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html)

进程:电脑中的一个后台程序,如一个java程序,一个360软件
线程:进程中可调度的最小单位,如360软件中的查杀,修复,加速....
相关关键字: lock Synchronized ReentrantLock ReadWriteLock notify notifyAll sleep join start run cas Executor框架

  1. SingleThreadExecutor 线 程 池
    这 个 线 程 池 只 有 一 个 核 心 线 程 在 工 作 , 也 就 是 相 当 于 单 线 程 串 行 执 行 所
    有 任 务 。 如 果 这 个 唯 一 的 线 程 因 为 异 常 结 束 , 那 么 会 有 一 个 新 的 线 程 来
    替 代 它 。 此 线 程 池 保 证 所 有 任 务 的 执 行 顺 序 按 照 任 务 的 提 交 顺 序 执 行 。
  2. FixedThreadPool 线 程 池
    FixedThreadPool 是 固 定 大 小 的 线 程 池 , 只 有 核 心 线 程 。 每 次 提 交 一 个
    任 务 就 创 建 一 个 线 程 , 直 到 线 程 达 到 线 程 池 的 最 大 大 小 。 线 程 池 的 大 小
    一 旦 达 到 最 大 值 就 会 保 持 不 变 , 如 果 某 个 线 程 因 为 执 行 异 常 而 结 束 , 那
    么 线 程 池 会 补 充 一 个 新 线 程 。
    FixedThreadPool 多 数 针 对 一 些 很 稳 定 很 固 定 的 正 规 并 发 线 程 , 多 用 于
    服 务 器 。
  3. CachedThreadPool 线 程 池
    CachedThreadPool 是 无 界 线 程 池 , 如 果 线 程 池 的 大 小 超 过 了 处 理 任 务
    所 需 要 的 线 程 , 那 么 就 会 回 收 部 分 空 闲 ( 60 秒 不 执 行 任 务 ) 线 程 , 当
    任 务 数 增 加 时 , 此 线 程 池 又 可 以 智 能 的 添 加 新 线 程 来 处 理 任 务 。
    线 程 池 大 小 完 全 依 赖 于 *** 作 系 统 ( 或 者 说 JVM) 能 够 创 建 的 最 大 线 程
    大 小 。 SynchronousQueue 是 一 个 是 缓 冲 区 为 1 的 阻 塞 队 列 。
    缓 存 型 池 子 通 常 用 于 执 行 一 些 生 存 期 很 短 的 异 步 型 任 务 , 因 此 在 一 些 面
    向 连 接 的 daemon 型 SERVER 中 用 得 不 多 。 但 对 于 生 存 期 短 的 异 步
    任 务 , 它 是 Executor 的 首 选 。
  4. ScheduledThreadPool 线 程 池
    ScheduledThreadPool: 核 心 线 程 池 固 定 , 大 小 无 限 的 线 程 池 。 此 线 程
    池 支 持 定 时 以 及 周 期 性 执 行 任 务 的 需 求 。 创 建 一 个 周 期 性 执 行 任 务 的 线
    程 池 。 如 果 闲 置 , 非 核 心 线 程 池 会 在 DEFAULT_KEEPALIVEMILLIS 时
    间 内 回 收 。

Synchronized 既 能 保 证 可 见 性 , 又 能 保 证 原 子 性 , 而 volatile 只 能
保 证 可 见 性 , 无 法 保 证 原 子 性 。volatile不能保证原子性的原因是因为java中的运算是非原子 *** 作

ThreadLocal 和 Synchonized 都 用 于 解 决 多 线 程 并 发 访 问 , 防 止 任 务在 共 享 资 源 上 产 生 冲 突 。 但 是 ThreadLocal 与 Synchronized 有 本 质的 区 别:Synchronized加锁,牺牲了时间,是以"时间换空间的方式",ThreadLocal是每一个线程有副本,根除了变量共享,以"空间换时间".

wait和sleep :相同是都可以让cpu浪费一段执行时间。最大的不同是在等待时 wait 会释放锁,而 sleep 一直持有锁。Wait 通常被用于线程间交互,sleep 通常被用于暂停执行。

在竞争程度低的时候,sync和cas效率基本一直,当竞争激烈的时候,sync性能要高于cas

cas: 内存值,预期值,新值。 当内存值与预期值相等的时候,将内存值改为新值的一个循环比较赋值 *** 作

公平锁与非公平锁: 就是加锁之后,有很多其他线程先后到达获取该锁,如果解锁后,按照顺序获取下一个执行的线程,那就是公平锁,否则就是非公平锁,synchonized就是非公平锁

并发和并行:并发可以说是一种并行的假象。你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。并发的关键是你有处理多个任务的能力,不一定要同时。并行的关键是你有同时处理多个任务的能力。所以我认为它们最关键的点就是:是否是『同时』。

作者:知乎用户
链接:https://www.zhihu.com/question/33515481/answer/58849148
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

所以,并发就是:你看似他在“同时”处理多个任务,实际上,他没有同时处理,而是利用时间碎片在执行每个任务。这就是我开始说的,并发是并行的一种假象,而并行则是真正的,同时处理多个任务。
再举个栗子:单个cpu处理两个任务是并发,双cpu处理两个任务就是并行。

对象锁和类锁:对象锁就是对普通方法加锁,锁加在当前方法所在的对象。类锁就是对静态方法加锁,锁加在该方法所在对象的每个实例。继续解释,对象锁防止的是多个外部同时访问该对象的普通方法,而造成数据不同步,每个对象都有一把锁,且唯一。类锁是同个对象多次实例化,防止多个实例同时调用该静态方法,而造成数据不同步,所有实例都是同一把锁。
如是:如果synchronized某个普通方法,那么当仅有一个实例对象的时候,多线程访问该实例普通方法,那么将会阻塞,每次执行一个线程。如果synchronized某个静态方法,那么当有多个线程,每个线程有一个实例对象的时候,访问该静态方法,那么将会阻塞,每次执行一个线程。

HashMap不是线程安全的;Hashtable线程安全,但效率低,因为是Hashtable是使⽤用synchronized的,所有线程竞争同一
把锁;⽽而ConcurrentHashMap不不仅线程安全⽽而且效率⾼高,因为它包含一个segment数组,将数据分段存储,给每⼀段数据配一把锁,也就是所谓的锁分段技术。
HashMap不是线程安全的的主要原因:多线程下,put时key相同会导致value覆盖,数据丢失。多线程扩容,hashmap会导致链表产生环形结构,导致产生问题。

分布式锁:1、zookeeper,高并发支持不好,需要动态创建删除瞬时节点,锁维护消耗性能较高。2、memcached,支持高并发,但不支持持久化,重启即丢失缓存锁。3、redis ,支持高并发,且可以持久化,setnex方法即可,一定要设置超时时间,避免死锁;

同步/异步:同步,执行开始调用另一个,必须等待另一个完成,返回结果,然后继续进行下去。异步,执行开始,调用另一个瞬间继续进行下一步,如果需要调用结果,那么等另一个执行完,会通知调用方。

死锁、饥饿、活锁:死锁,多线程之间争抢资源,相互等待对方释放资源锁。饥饿,多线程之间由于优先级的原因,导致一些低优先级的线程一直得不到执行。活锁,多线程之间“谦让”资源,锁在多线程之间“推来推去”。

指令重排:就是执行顺序被优化后执行的一种现象。为什么要指令重排?为了优化。优化什么?优化的是(个人猜测)预编译期间,程序发现有些指令的加载顺序会使 执行“流水线”(cpu执行有一个流水线)不停的中断,浪费时间,为了减少流水线停顿,那么将一些指令提前执行。即重排。那么所有指令都可以重排吗???不是的。

join、yield:join关键字,是为了暂停其他线程,执行完当前线程后再执行其他线程,否则当前线程一直处于阻塞状态。yield关键字,是为了暂停当前线程,让出当前线程的cpu,当前线程进入一个线程的就绪状态,而非阻塞状态。

ReentrantLock:可重入锁,即可以在获取到一次该锁后,在run中再次获取该锁,其中lock.lockInterruptibly();是加一个可以打断的锁. t.interrupt();为打断该锁. lock.isHeldByCurrentThread(); 判断该锁是否还持有该锁.如无可以释放该锁,释放方法为lock.unlock(); 尝试获取锁tryLock();尝试获取锁立即返回.还可以传入参数,时间和单位,指定时间内获取锁;

ReadWriteLock:读写锁,就是给读和写两个 *** 作分别加锁,使用上没有什么特殊的地方。不同的是,当加锁后,读锁之间相互并不影响,而读写以及写写直接会互斥。这样适合读多写少的模式。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5687515.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存