一、基本概念:

1.线程/进程

(1)状态

「Thread.State」:

  • NEW:创建了对象,但是没有start
  • RUNNABLE:Java线程中,将就绪态「Ready」和运行时「Running」统称为「Runnable」。当某线程被创建后,start被调用后,此线程就进入可运行线程池中,等待调用,获取CPU使用权,此时处于「Ready」,当「Ready」的线程获得了CPU时间片后变为「Running」
  • BLOCKED:线程处于阻塞状态
  • WAITING:等待,直到其他线程做出特定动作「中断或者通知」
  • TIMED_WAITING:超时等待「不同于Waiting,此状态是等待指定时间后自行返回」
  • TERMINATED:线程执行完毕

_![image.png](https://cdn.nlark.com/yuque/0/2020/png/682915/1594702421214-f1225771-c639-42a0-83a8-b2a92b8f05c8.png#align=left&display=inline&height=386&margin=%5Bobject%20Object%5D&name=image.png&originHeight=771&originWidth=1155&size=321847&status=done&style=none&width=577.5)_
「注意」:waiting-不见不散 time-waiting-过时不候

(2)资源

(3)概念

2.并发/并行

(1)执行顺序

(2)安全性

(3)概念

3.案例

(1)「多线程」售票员卖票

「多线程问题」线程操作资源类

「Lambda表达式」 拷贝中括号【里面放置函数体需要的参数】,写死右箭头,落地大括号【当只有一句简单的操作代码时可以省略大括号】

「Lambda表达式」函数接口有且只有一个方法【@FunctionalInterface】

「Lambda表达式」接口可通过default实现方法

「Lambda表达式」定义静态static方法

  1. package com.wtz.juc.saleTicket;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. /**
  5. * @author tiezhu
  6. * @Date 2020/7/11 Sat
  7. * Company dtstack
  8. */
  9. class Ticket {
  10. private int number = 300;
  11. private final Lock lock = new ReentrantLock();
  12. public void sale() {
  13. lock.lock();
  14. try {
  15. if (number > 0) {
  16. System.out.println(Thread.currentThread().getName() + "\t 卖出第 " + (number--) + " 张,还剩 " + number + " 张");
  17. }
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. } finally {
  21. lock.unlock();
  22. }
  23. }
  24. }
  25. public class CodeOne {
  26. public static void main(String[] args) {
  27. final Ticket ticket = new Ticket();
  28. new Thread(() -> {
  29. for (int i = 0; i < 400; i++)
  30. ticket.sale();
  31. }, "Thread A").start();
  32. new Thread(() -> {
  33. for (int i = 0; i < 400; i++)
  34. ticket.sale();
  35. }, "Thread B").start();
  36. new Thread(() -> {
  37. for (int i = 0; i < 400; i++)
  38. ticket.sale();
  39. }, "Thread C").start();
  40. /* new Thread(new Runnable() {
  41. public void run() {
  42. for (int i = 0; i < 40; i++) {
  43. ticket.sale();
  44. }
  45. }
  46. }, "Thread A").start();
  47. new Thread(new Runnable() {
  48. public void run() {
  49. for (int i = 0; i < 40; i++) {
  50. ticket.sale();
  51. }
  52. }
  53. }, "Thread B").start();
  54. new Thread(new Runnable() {
  55. public void run() {
  56. for (int i = 0; i < 40; i++) {
  57. ticket.sale();
  58. }
  59. }
  60. }, "Thread C").start();*/
  61. }
  62. }

(2)8锁问题

判断/干活/通知

(3)总结

线程不是按照执行顺序执行的,而是根据争抢资源的结果「先抢到的先执行」

访问同一个资源类,锁的是当前对象,现象是即使对象有多个同步方法,但是一个线程只能访问一个同步方法,因为同步锁锁的是整个资源类对象,而不是某个同步方法

普通方法不与同步方法争抢资源

「静态同步锁」Static 属于整个类,静态同步锁锁整个类,普通的同步锁锁对象

二、JUC

1.Java.util.concurrent

2.Java.util.concurrent.locks

(1)可重入锁【ReentrantLock】

try - finally 开始前先上锁,最后一定要释放锁【可通过设置 idea 快捷键保证自己不会忘记在 finally 释放锁】

3.Java.util.concurrent.atomic

4.Java.util.ConcurrentModificationException

(1)故障现象

抛出 Java.util.ConcurrentModificationException 异常

(2)原因

多线程并发争抢资源导致数据写入异常

(3)解决

将ArrayList转化为Vector【并发性下降】

Collections.synchoronizedList(new ArrayList<>())【版本较老】

CopyOnWriteArrayList()【写时复制】读写分离

(4)优化建议

Map -> concurrentHashMap

Set -> CopyOnWriteSet

List -> CopyOnWriteArrayList