Java多线程

并发

线程状态

Debug调试,线程模式。
在这里插入图片描述

  • java:6种状态

    • NEW(新建)—— start
    • RUNNABLE(就绪 | 运行 | 阻塞I/O)—— cpu 调度
    • TERMINATED(终结)—— 代码执行完毕
    • BLOCKED(阻塞)—— 获取锁失败
    • WAITING(等待) ——获得锁的wait()
    • TIMED_WAITING(等待有时限) ——获得锁的wait(long)或者sleep(long)
  • 操作系统:5种

    • 新建
    • 就绪(可以分到CPU时间)
    • 运行(分到CPU时间)
    • 终结
    • 阻塞(分不到CPU时间)

线程池7个参数

  1. corePoolSize ——核心线程
  2. maximumPoolSize ——最大线程(包含救急线程)
  3. keepAliveTime——生存时间(空闲救急线程生存时间)
  4. unit——时间单位
  5. workQueue——阻塞队列(核心线程满后,放入任务队列,任务队列满启用救急线程)
  6. threadFactory——线程工厂
  7. handler——拒绝策略(当核心线程满,任务队列满,救急线程满时,拒绝任务策略)
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
        2,
        3,
        0,
        TimeUnit.MILLISECONDS,
        workQueue,
        r -> new Thread(r,"myThread"+c.getAndIncrement()),
        new ThreadPoolExecutor.AbortPolicy()
);
拒绝策略
//AbortPolicy():抛出异常
//CallerRunsPolicy():由调用者执行
//DiscardPolicy():丢弃任务
//DiscardOldestPolicy():丢弃队列中最老任务

sleep VS wait

共同点:都会暂时放弃CPU使用权,进入阻塞状态。
不同点:

  • 方法归宿不同
    • sleep是Thread的静态方法。
    • wait是Object成员方法。每个对象都有。
  • 醒来时机不同
    • wait(long) 和wait() 能被notify唤醒
    • 都可以被打断唤醒。
  • 锁特性不同
    • wait方法必须先获取wait对象锁,sleep则不用
    • wait方法会释放锁,允许其他线程获取锁。
    • sleep如果在synchronized代码块中执行,并不会释放对象锁。

线程同步

synchronized :可以使用wait、notify实现。
lock:可以使用条件变量实现。

lock VS synchronized

  1. 语法层面:
    • synchronized 是关键字,源码在jvm中,C++实现。
    • Lock是接口,源码jdk提供,Java实现。
    • synchronized会自动释放锁;Lock手动释放锁。
  2. 功能层面
    • 都是悲观锁,具备基本的互斥、同步、锁重入功能。
    • Lock提供许多synchronized 不具备的功能,如获取等待状态、公平锁、可打断、可超时、多条件变量。
    • Lock适合不同场景的实现,ReentrantLock、ReentrantReadWritreLock。
  3. 性能层面
    • 在没有竞争时,synchronized做了很多优化,偏向锁、轻量级锁。
    • 在竞争激烈时,Lock有更好的性能。

公平与非公平

条件变量

  • await()
    会释放锁,并把线程加入等待队列(waiting queue)中。
  • signal()
    唤醒waiting queue中线程,加入block queue阻塞队列最后。

volatile能否保证线程安全?

线程安全3个方面:可见性、有序性、原子性。
不能,volatile只能保证可见性、有序性。

可见性原因、解决

原因:当一段代码执行次数极多时,会被JIT即时编译器优化,替换,下次执行JIT优化后的代码。导致不能读取已经更改的值。
解决:

  1. 不使用JIT热点代码的优化:-Xint;
  2. volatile修饰,保证可见性。

volatile位置

写操作:volatile的变量放在最后,保证上面写操作都被写屏障保护,保障不会出现先赋值在写操作。
读操作:volatile的变量放在第一个,保证下面都被读屏障保护,保障不会读取到未赋值的变量。

悲观锁与乐观锁

悲观锁:

  1. 就是线程必须占有了锁才能操作共享变量,每次只有一个线程占锁成功,获得锁失败的线程都要等待。
  2. 线程会从运行到阻塞频繁上下文切换,影响性能。
  3. synchronized和lock锁都会有几次重试操作,减少阻塞。

乐观锁:

  1. 无需加锁,每次只有一个线程修改共享数据成功,其他失败线程不用停止,不断尝试直到成功。
  2. 线程是一直运行,不涉及线程上下文切换。
  3. 多核CPU,线程数不应超过cpu核数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值