Warning: Undefined array key "nDRpQp" in /www/wwwroot/106.12.87.161/wp-config.php on line 1

Warning: Undefined array key "RxVNgs" in /www/wwwroot/106.12.87.161/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 1
Java技术–并发 – 磊宝de小屋
Java技术–并发

线程的创建方式:

  • 继承Thread类:
    • 最直接的方式,重写Thread类的run()方法
      • run()方法中不定义任何逻辑,需要重写来进行定义具体的业务逻辑
    • 实例化该类后,通过start()启动线程【start()方法内部会自动执行run()方法】
    • 缺点:会导致不能继承其他的类,限制性较大。
class MyThread extends Thread{
    @Override
    public void run(){
    具体逻辑.........
    }
}
public static void main(){
   MyThread myThread = new MyThread();
   myThread.start();
}
  • 实现Runnable接口:
    • 大体与Thread类的功能差不多,但是是通过接口实现的方式。
class MyThread implements Runnable{
    @Overrid
    public void run(){
      具体逻辑......
    }
}

public static void main(){
  Thread t=new Thread(new MyRunnable);
  t.start();
}
  • 实现Callable接口
    • 可以有返回值,并且可以多线程处理一份资源
class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        // 线程执行的代码, 这里返回一个整型结果
        return 1;
    }
}

public static void main(String[] args) {
    MyCallable task = new MyCallable();
    FutureTask<Integer> futureTask = new FutureTask<>(task);//将callable类包装进FutureTask
    Thread t = new Thread(futureTask);
    t.start();

    try {
        Integer result = futureTask.get();  // 获取线程执行结果
        System.out.println("Result: " + result);
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
}
  • 使用线程池(Excutors):
    • 一种规范管理多线程的方式,避免了线程创建和销毁的开销
Class Task implement Runnable{
  @Override
  public void run(){
  具体逻辑.............
  }
}
public static void main(){
 ExecutorService executor= new Executors.newFixedThreadPool(10)//设置线程池大小:10
for(int i;i<10;i++){
 executor.submit(new Task());
   }
 executor.shutdown;
 }

如何终止线程:

  • 使用sleep()休眠线程,然后调用interrupt方法使线程标记为中断状态,在线程提交完此次任务后自我了断
  • 使用stop()暴力停止:但是会有很大不好的后果,已被废弃
  • 使用interrupt方法标记为中断状态,在run方法中判断线程状态,如果是中断则return或手动抛出异常

线程的状态:

  • New:刚刚被创建,还未start(),初始状态
  • Runnable:调用了start(),正在运行状态
  • Blocked:正在等待阻塞状态
  • Waitting:正在等待其他线程完成指定动作,等待状态
  • Timed_waitting:人为设置了等待时间的等待状态W
  • Terminated:线程完成任务,终止状态

Sleep和Wait的区别:

  • 锁处理:Sleep不释放锁,抱着锁睡觉(但会释放CPU)。而wait方法会释放锁
  • 使用位置:sleep可以在任何位置使用,而wait必须在synchronzed代码块/方法中使用
  • 唤醒条件:sleep睡醒后就苏醒,而wait必须要等待notify()来唤醒
  • 用途:sleep用于暂停线程,而wait用于线程间的通信与协作
  • Wait和Blocked的区别:
    • Wait是主动暂停,用于与其他线程的写作。而Blocked是抢锁失败,进入阻塞
    • Wait需要显式的唤醒,而Blocked会主动去抢锁

线程间的通信方式:

  • wait()、notify()、notifyAll():
    • 最基础的通信方式
  • Lock()和Condition接口:
    • 提供了一种比synchronzed更轻量灵活的锁机制
  • volatile关键字:
    • 用volatile关键字修饰的变量再被更改后会立即通知其他线程,保证变量的可见性
  • Semaphore信号量:一个计数的信号量,可以控制特定资源的访问

优雅的停止线程的方式

不应该暴力的停止(如stop)。而是应该通过逻辑控制停止

  • 通过共享标志变量来控制:
    • 用volatile关键字修饰一个变量,当工作线程检测到为false时停止(设置中断标志)
  • 直接使用线程中断机制:
    • 通过Tread.interrupt()来标识中断标志,当线程执行完当前任务则会自动中断。

如何保证线程安全:

  • synchronized关键字:同步代码块或方法,确保同一时间只能有一个线程进入代码块
  • volatile关键字:作用于变量,确保所有线程都能及时看到该变量的值
  • 使用ReentrantLock可重入锁:实现Lock接口。比synchronized更加强大的锁机制,就是那种需要fianlly解锁的那种
  • 使用JUC提供的原子类:如AtomicInterger
  • 使用并发安全的集合:如ConcurrentHashMapper;CopyOnWriteArryayList;ConcurrentLinkedQueue等

Java中常用的锁:

  • Synchronized内置锁:
    • 是一种可重入锁,公平锁
    • 当没有其他线程竞争时,会使用无锁、偏向锁、轻量级锁、重量级锁
  • ReentrantLock可重入锁:
    • 默认非公平锁
    • 比起Synchronized更加灵活功能高级,如定时锁等待,是否公平
  • ReadWriteLock读写锁:
    • 允许多个读取者但是只允许一个写入者,用于读远多于写的情况
  • 自旋锁(思想):线程在等待锁时会持续循环检查锁是否可用,通常用于锁等待时间很短的情况,通常用CAS替代
  • 锁的公平性:
    • 公平:按先后顺序来
    • 不公平:按线程获取锁的CAS来
    • 非公平锁的吞吐量更大:如果直接抢到锁就不需要睡觉了,线程的状态来回转换很耗时耗性能

synchronized的四种量级

  • 无锁:没有任何线程持有锁
  • 偏向锁:在锁内部维护一个线程ID,如果该线程再次获取锁则直接进入。当有线程竞争锁时升级为轻量级锁
  • 轻量级锁:当线程轻微竞争时,其他线程需要自旋来等待锁的释放,自旋不断尝试获取锁,占用CPU
    • 后期Java废弃了偏向锁,因为现代应用持续的并发都比较高,偏向锁的撤销反而浪费性能
  • 重量级锁:当线程激烈竞争时,其他线程获取不到锁会直接进入阻塞状态。

ThreadLocal:

在Thread内部维护了一个ThreadLocalMap字段,以map的形式存储数据,以做到内部数据不污染Thread本身,具体内部存储什么数据由开发者定义。

比如在Thread Local的工具类中创建:

private static ThreadLocal<Long> userIdHolder = new ThreadLocal<>();

会创建一个userIdHolder的Key,而具体的value通过userIdHolder.set设置

若再创建一个private static ThreadLocal<Long> userNameHolder = new ThreadLocal<>();

同理会在ThreadLocalMap内部创建一个userNameHold的Key,以为当前线程以一种解耦的方式赋成员变量

注意:key是弱引用,而value是强引用,所以当业务逻辑走完时必须要remove清理强引用value,防止OOM

形成死锁的四个条件:

  • 互斥:首先此份资源不允许多个线程使用
  • 持有并等待:占着茅坑不拉屎,线程A持有了资源1,后续需要资源2,但是资源2被线程BNTR了,线程1死等而不释放资源1
  • 不可剥夺:线程持有了此资源,必须完成任务才肯释放资源
  • 环路等待:两个线程获取资源的顺序形成了环形。

线程池:

主要是为了统一管理多线程,并且减少频繁的线程创建和销毁的性能浪费。

根据阿里巴巴Java开发手册,只允许使用ThreadPoolExecutore,可以通过参数配置来实现其他线程池的功能。

  • Executores:最简单便捷的线程池,但是默认核心线程数无界,可能会导致线程过多而OOM,所以更加推荐使用ThreadPoolExecutor手动配置
  • ThreadPoolExecutore:需要指定7个核心线程参数
    • 核心线程数:IO密集型任务一般选择CPU核心数的两倍
    • 最大线程数:只有当任务队列爆满才会扩容线程数
    • 存活时间:当线程数>核心线程数,空闲时间大于存活时间的线程会被销毁
    • 任务队列:用于指定任务队列
    • 拒绝策略:
      • 直接抛异常:一种“快速失败”的思想,可用于如验证码、抢单场景
      • 调用者执行(CallerRunsPolicy):让提交任务的线程自己执行,可能会堵塞主线程,不推荐
      • DiscardPolicy:直接丢弃新任务
      • DiscardOldestPolicy:直接丢弃最老任务,与上一个都是用于容忍度较高的场景,比如点赞。
  • ScheduledThreadPool:支持定时或周期性的执行任务
  • FixedThreadPool:无最大线程数,线程数固定,因为默认使用LinkedBlockQueue的无界队列而不便于修改,被许多公司禁止使用
  • CacheThreadPool:无最大线程数,可能会导致OOM,被禁止使用
  • SingleThreadPool:只有单个线程,当线程阻塞时才会新建线程,适合低并发且强调任务提交顺序

任务队列:

  • LinkedBlockQueue(链表阻塞队列):
    • 默认无界,吞吐量大,适合IO密集型任务
    • 内部使用了两把锁,允许并行出入队列
    • 链表节点的创建消除对内存有压力
  • ArrayBlockQueue(数组阻塞队列):
    • 必须指定大小,因此内存稳定,避免OOM
    • 内部只有一把锁,出入对互斥。因此吞吐量更低
    • 继承了数组的特性,所以无法动态扩容
  • SynchronousQueue(同步移交队列):
    • 不存储元素,每一个任务必须等待消费,否则会阻塞生产者
    • 适合任务量大但处理极速的场景,吞吐量大
  • PriorityBlockingQueue(优先级队列):
    • 无界,支持按照优先级排列任务
    • 适合VIP用户等场景
  • DelayQueue(延迟队列):
    • 指定延迟时间到了才允许进行处理
    • 用于订单超时未支付等场景

任务队列爆满的应对措施:

  • 查找根因,是代码问题还是SQL问题,查询慢SQL
  • 重写扩容线程逻辑:默认的逻辑是核心线程繁忙会将任务丢尽阻塞队列。当阻塞队列满了才会去根据最大线程数扩大线程数量。可以参考Tomcat的做法重写逻辑,当核心线程繁忙后立即扩大线程数
  • 自定义拒绝策略:参考开源方法,将任务丢入消息队列中或持久化到数据库,后续再捞出来做消息补偿。而非选择常用的CallerRunsPolicy,这可能会导致主线程繁忙甚至是Tomcat直接挂掉

线程池种类:

  • Executor
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇