多线程
多线程
1 概念
1.1 程序
- 为了完成某个任务或功能,选择某个编程语言而编写的一组代码指令的集合
1.2 进程
- 程序的一次运行,是操作系统管理和调度的最小单位,每一个进程之间内存是相互独立的,如果进程之间要通信比较麻烦,可以通过文件,或网络通信方式等
1.3 线程
-
是进程中的其中一条执行路径,是 CPU 调度任务的最小单位
- 线程是共享同一个进程的内存
2 如何开启主线程以外的线程
2.1 方式一:继承 java.lang.Thread 类
-
步骤
- ①继承Thread类
② 重写 public void run(){} 编写线程体,即该线程需要完成的任务代码 ③ 创建线程对象 ④ 启动线程:线程对象.start();
2.2 方式二:实现 java.lang.Runnable 接口
-
步骤
- ①实现java.lang.Runnable接口
② 实现 public void run(){} 编写线程体,即该线程需要完成的任务代码 ③ 创建线程对象 ④ 启动线程:借助 Thread 类的对象 new Thread(自定义线程对象).start();
2.3 经典面试题
-
两种方式的区别
- 区别:
(1)继承 Thread 类会有单继承的限制 实现 Runnable 接口不会有单继承的限制 (2)继承 Thread 类的方式,共享数据方面比较麻烦,使用 static 方式 实现 Runnable 接口,共享数据时,只需要共用同一个的 Runnable 接口的实现类的对象即可 (3)继承 Thread 类的方式,同步的锁的选择要么选择一个 static 对象作为锁,要么选择“类名.class 即当前类 Class 对象” 实现 Runnable 接口,同步锁可以直接选择 this 对象
3 线程安全问题
3.1 前提条件
- (1)有多个线程 (2)共享数据 (3)多条语句操作共享数据
3.2 解决方法
-
同步 synchronized
- 形式 - 同步代码块 - synchronized(锁对象){ 同步代码,即需要加锁的代码
}
- 同步方法 - synchronized [修饰符] 返回值类型 方法名(形参列表)抛出的异常列表 - 同步锁 - (1)任意类型的对象
(2)保证使用共享数据的多个线程,共用同一个锁对象
- 锁的范围 - 同步代码块:范围
(1)不能太大:机会不均匀 (2)不能太小:安全问题没解决 (3)最好锁一次任务代码
- 同步方法的锁: - 静态方法的锁:当前类的Class对象,即当前类名.class
非静态方法的锁:当前对象,this
4 线程通信
4.1 问题:生产者消费者问题
-
问题
-
现象描述
-
有多个线程共享一个缓冲区(例如:数据仓库,文件等),有的线程往里放数据,有的线程往外取数据
-
问题有两个
-
问题:线程安全问题
- 因为有共享数据
- 如何解决:同步
-
问题:缓冲区大小有限的
- 如何解决:线程通信
-
-
-
-
4.2 线程通信的方法
-
(1)wait() (2)notify()和 notifyAll()
- 在java.lang.Object - 为什么? - 线程通信依赖于锁对象,即wait()和notify()是由锁对象调用 - 锁对象可能是任意类型的对象,那么这些方法只能在Object类中声明
-
面试题:wait()和 sleep()的异同?
-
同
- 这两个方法都会导致当前线程从运行状态到阻塞状态
-
不同
-
从阻塞回到就绪状态
- sleep()睡眠时间到了
- wait()也可以设置时间,但更多时候是通过 notify()
-
声明的类不同
- wait 是 Object 中,非静态方法
- sleep 是 Thread 类中,静态方法
-
锁释放问题
-
sleep:不会释放锁的
- 例如:在卫生间睡着了,锁还在手上
-
wait():会释放锁的
- 例如:抢到锁了,但是因为一些条件不满足,就释放锁,由其他线程执行
-
-
-
5 java.lang.Thread
5.1 方法
-
1、获取线程名称的方法
- getName()
-
2、获取当前线程对象
- Thread.currentThread()
-
3、线程休眠
- Thread.sleep(毫秒)
- Thread.sleep(毫秒,纳秒)
-
4、线程的优先级
-
getPriority()
-
setPriority()
-
优先级的范围是 1-10
- MAX_PRIORITY:10
- MIN_PRIORITY:1
- NORMAL_PRIORITY:5
-
-
注意:业务逻辑不能依赖于优先级
-
-
5、加塞
-
join()
- 这句代码写在那个线程体中,哪个线程被加塞,被调用这个 join()的线程加塞
-
-
6、run():所有线程都要写
-
7、start():启动线程