复习
线程的概念
本质上就是一条执行路径
作用 : 使代码同时可以执行多个事物
(其实是线程之间的高频转换,不断的抢夺CPU执行权,抢到就有执行权,但有时间限制--时间片)
线程的相关名词
进程 : 一个正在进行的程序
线程 : 一条执行路径
每个线程都有自己的栈内存,
而多个线程共享一个堆内存
主线程 : 进程在开启时自带一个线程,该线程被称为主线程
子线程 : 除主线程外,其他线程都是子线程
多线程 : 一个进程中有多个线程
前台线程 : 线程默认为前台线程 一个进程中只要有前台线程存活,那么该进程就不会被系统所回收
(前台线程执行完,有一段时间的延迟,可以让后台进程执行一段)
守护线程(后台线程) : 使用方法对线程进行设置 一个进程中所有前台线程都被销毁,那么该进程将会被系统回收,此时不管是否有守护线程存活
线程的组成
CPU时间片 : 含义 : 线程获取到CPU执行权后,可执行的时间
内存 : 含义:线程在使用时占用的内存,一个线程一个栈,多个线程共享一个堆
逻辑 : 含义:编写线程执行时的代码顺序
线程的创建
方案1:创建Thread的子类对象
方式1:普通方式 步骤: 1,创建一个类 2,使其继承与Thread 3,重写run方法 4,创建该类对象方式2:使用匿名内部类创建Thread的子类对象(合并123步骤) 步骤: Thread 对象名 = new Thread(){ 重写run方法 };
方案2:将线程(Thread)与线程任务(Runnable)分开
方式1:普通方式 步骤: 1,创建一个类 2,使其Runnable接口 3,重写run方法 4,创建该类对象 5,创建Thread对象,并传入该类对象方式2:使用匿名内部类的形式创建Runnable的子类对象 步骤: 1,使用匿名内部类创建Runnable的子类对象 Runnable 对象名 = new Runnable(){ 重写run }; 2,创建Thread对象,并传入Runnable的对象 Thread 对象名2 = new Thread(对象名);
线程的使用
启动
线程对象.start()销毁
线程已经启动不受控制 线程在启动后,将执行run方法中的代码,当run中的代码执行完毕后,线程会等待被系统回收 所以想让线程提前结束,得想办法run中的代码提前执行完毕名称
设置线程名称 方式1:在创建线程对象时传入 方式2:使用线程对象.setName进行设置,注意:在线程启动之前 获取线程名称 String 线程名称 = 线程对象.getName(); 注意: 主线程名称为main 子线程名称默认为:Thread-0,Thread-1,....获取当前线程
Thread 当前线程对象 = Thread.currentThread();优先级
作用:提高线程抢夺到CPU执行权的概率 设置优先级 线程对象.setPriority(优先级); 注意: 优先级取值范围:1~10 获取优先级 int 变量名 = 线程对象.getPriority();休眠
作用:让线程停止执行,也不在抢夺CPU执行权 语法: Thread.sleep(休眠时间);礼让
作用:让线程让出本次抢夺到的CPU执行权,然后重新参与抢夺 语法: Thread.yield();合并
作用:将两个线程合并为一个线程 语法: 线程对象.join(); 注意: 将线程对象所属的线程合并到当前线程,此时将先执行线程对象所属的线程剩余的代码,当执行完毕后,在执行当前线程剩余的代码守护线程
语法: 线程对象.setDaemon(true);
线程的生命周期
创建 就绪 运行 消亡 阻塞 等待 无限期 有限期
今日
线程安全问题
原因
多个线程操作同一个数据,会导致线程安全问题
解决思路
保证同时只能有一个线程操作该数据
方案一 : 同步代码块 锁对象就是自己建的
语法 synchronized(锁对象){ 要同步的代码 (同时操作的数据) }注意 :
1.所有对象都可以作为锁对象 2.多个线程的锁对象要是同一个对象
方案二 : 同步方法 this(调用这个方法的对象就是锁对象)
语法 访问权限修饰符 synchronized 返回值类型 方法名(形参列表){ }int a; String b; char c; a.方法(); //此时a就是锁对象 ...注意 :
1.同步方法的锁对象是this 2.多个线程的锁对象要是同一个对象
方案三 : 同步静态方法 锁对象就是JVM加载的该类对象
类对象
JVM加载类时会生成一个对象,该对象就是该类的类对象,一个类只有一个类对象(因为类只会加载一次)
语法 访问权限修饰符 synchronized static 返回值类型 方法名(形参列表){ }注意 :
1.同步静态方法的锁对象时该类的类对象 2.多个线程的锁对象要是同一个对象
死锁 (主动避免)
原因
多个线程互相持有对方所需的锁资源例子
Object A = new Object(); Object B = new Object(); //创建两个对象,作为两把锁 线程1: xxx synchronized (A){ //锁A在外 xxx synchronized (B){ //锁B在内 xxx } } //当启动两个线程,有一种可能是 //线程1进入A锁中,线程2进入B锁中 //此时不管谁抢到执行权,因为要进入下一个锁 //但此时B锁被线程2占用,A锁被线程1占用,无法进入 线程2: xxx synchronized (B){ //锁B在外 xxx synchronized (A){ //锁A在内 xxx } }避免的思路
不要在同步中使用同步
经常会说要在同步范围内,如何辨别
有synchronized就是同步的范围
线程间通讯
让两个线程之间通讯--->一般就是叫醒/休眠操作
注意
1,线程间通讯的方法由Object提供 2,只能在同步中使用 3,只能使用所在的同步的锁对象调用唤醒 :
notify():随机唤醒一个 notifyAll():唤醒所有注意 :
只能唤醒以同一个对象调用wait方法的线程
休眠 :
wait():无限期休眠 wait(int ms):有限期休眠,ms毫秒 wait(int ms,int ns):有限期休眠,更精准,ns纳秒注意 :
参数就是休眠时间,ms毫秒,ns纳秒
wait与sleep的区别 :
1.wait在休眠期间会释放所持有的锁资源,sleep不会 2.wait必须在同步中使用,sleep没有限制 3.wait必须使用所在的同步的锁对象调用,sleep使用Thread类或Thread类的对象调用 4.wait由Object提供,sleep由Thread类提供
生产者与消费者模式
设计模式
作用:解决特定问题的思路 生产者与消费者模式解决的是进销存业务生产 无限生产 销售 无限销售 工厂 生产的方法 出货的方法 库存数量 商品数量上限:100 商品数量下限:0
作业
1,整理笔记 2,使用两个线程一个线程打印大写字母,一个打印小写字母 打印结果如:aAbBcC... 3,使用两个线程一个线程打印数字1~52,一个打印字母a~z 打印结果如:12a34b56c... 4,使用代码讲述龟兔赛跑 5,写一个三线程死锁 6,生成者与消费者模式 7,一个生成手机的厂商, 生成的手机型号为T3,颜色,随机从(红,黄,蓝,黑,银)中指定,CPU型号3980,手机屏幕大小7寸 请使用代码模拟该厂商生成与销售 其中生成工人有,张三,李四,王五 销售工人有,小白,小红,小黑 生产工人每2秒生产一个手机 销售人员0~10秒销售一个手机