多线程
start() 和 run() 的区别?
线程不一定执行 由cpu调度安排
继承Thread类
- 子类继承Thread类具备多线程能力
- 启动线程:子类对像.start()
- 不建议使用:避免oop单继承局限性
实现Runnable接口
- 具有多线程能力
- 启动线程: 传入目标对象+Thread对象.start()
- 推荐使用:避免单继承局限性,方便同一个对象被多个线程使用· ·3AQ`
实现Callable接口
静态代理
lambda表达式
- 避免匿名内部类定义过多
- 看起来更简洁
- 去掉了一些无意义的代码
函数式接口(Functional interface)的定义:
- 任何接口,入伙只包含唯一一个抽象的方法,那么就是一个函数式接口
- 对于函数式接口,我们可以通过lambda表达式来创建接口的对象
线程状态
线程方法
线程休眠sleep Thread.sleep
100ms==1s
- sleep (时间)指定当前线程阻塞的毫秒数;
- sleep存在异常 InterruptedException;
- sleep时间达到后线程进入就绪状态;
- sleep可以模拟网络延时,倒计时等
- 每一个对象都有一个锁,
- sleep不会释放锁;
线程礼让yield Thread.yield()
让当前正在执行的线程暂停,但不阻塞
让线程从运行状态转为就绪状态
让cpu重新调度,礼让不一定成功! 看cpu心情
join
join合并线程,代词线程执行完成后 在执行其他线程,其他线程阻塞
可以想象成插队
观测线程状态
- NEW
- RUNNABLE
- TIME_WAITTING
- TERMINATED
线程优先级
用数字表示 范围从1~10.
守护(daemon)线程
线程分为:用户线程 和 守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
线程同步机制
线程同步其实就是一个等待机制
队列和锁
锁机制
synchronized 默认锁的是run
死锁
都在等待对方的资源
解决方法:不要抱对方的锁 ,从代码块中拿出来
产生死锁的四个必要条件:
1.互斥条件:一个资源每次只能被一一个进程使用。 2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 3.不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 4.循环等待条件:若干进程之间形成- -种头尾相接的循环等待资源关系。
Lock(锁)
◆从JDK 5.0开始,Java提供了更强大的线程同步机制一通过 显式定义同步锁对 象来实现同步。同步锁使用Lock对象充当 ◆java.util.concurrent.locks.Lock接口是控制多个线程对共享 资源进行访问的工具。 锁提供了对共享资源的独占访问,每次只能有一-个线程对Lock对象加锁,线程开 始访问共享资源之前应先获得L ock对象 ◆ReentrantLock(可重入锁)类实现了Lock,它拥有与synchronized相同的并发性和内存语 义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释 放锁。
synchronized与Lock的对比
◆Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁,出了 作用域自动释放 ◆Lock只有代码块锁,synchronized有 代码块锁和方法锁 ◆使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展 性(提供更多的子类) ◆优先使用顺序: ◆Lock >同步代码块(已经进入了方法体,分配了相应资源) >同步方法(在方法体之外)
04线程协作
生产者消费者模式 问题
线程通信
应用场景:生产者和消费者问题 ◆假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将 仓库中产品取走消费 ◆如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到 仓库中的产品被消费者取走为止. ◆如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待, 直到仓库中再次放入产品为止.