java学习(三)之多线程

写在前面

啦啦啦,我又来了,第三天打卡成功!

今日学习内容

多线程

创建方式

  1. 继承Thread
    步骤:
    • 创建Thread子类
    • 重写run()方法,设置线程任务
    • 创建Thread子类对象
    • 调用start()方法开启线程
  2. 实现Runnable接口
    1. 步骤:
      • 创建Runnable接口的实现类
      • 重写run()方法,设置线程任务
      • 创建实现类对象
      • 创建Thread对象,构造方法中传递Runnable实现类对象
      • 调用start()方法开启线程
    2. 好处
      • 避免单继承的局限性:实现Runnable接口还能继承其他类,实现其他接口;
      • 增强程序扩展性:解耦,把线程任务和开启线程进行了分离(Thread构造方法中传递什么实现类对象,就执行什么线程任务)
  3. 匿名内部类
    格式:
    new 父类/Runnable(){
    //重写run方法
    };
    

方法

  1. java.lang.Thread的方法:
    1. 获取线程名称:String getName();
    2. 设置线程名称:void setName(String name);
    3. 使当前正在执行的线程以指定的毫秒数暂停,毫秒数结束之后,继续执行static void sleep(long millis);
    4. 获取当前正在执行的线程:static Thread currentThread()
    5. 创建Thread对象:
      1. Thread();
      2. Thread(String name);
      3. Thread(Runnable target);
      4. Thread(Runnable target, String name);
  2. java.lang.Object的方法:
    1. 唤醒此对象监视器的单个线程,继续执行wait()之后的代码,,若锁对象有多个等待线程,则随机唤醒: void notify();
    2. 唤醒此对象监视器的所有线程:void notifyAll();
    3. 当前线程等待:void wait();
    4. 当前线程以指定时间等待:void wait(long millis);

线程安全

多个线程访问共同的数据,会引发线程安全问题
解决方案:线程在访问共享数据时,无论是否失去了CPU的执行权,让其他线程只能等待,等当前线程结束,其他线程再执行。

线程同步

  1. 同步代码块
    1. 格式
      synchronized(锁对象){
      //可能会引发线程安全的代码
      }
      
    2. 注意
      1. 锁对象可以是任意对象(锁对象的作用:把此段代码锁住,只让一个线程执行此段代码块)
      2. 必须保证多个线程使用同一个锁对象,以保证同步【在Thread子类/Runnable实现类中声明成员变量“锁对象”】
  2. 同步方法
    1. 步骤
      1. 将访问共享数据的代码抽取出来,放到一个方法中
      2. 方法上加synchronized关键字
    2. 格式
      	修饰符 synchronized 返回值类型 方法名(){
      	//共享数据的代码块
      	}
      	修饰符 static synchronized 返回值类型 方法名(){
      	//共享数据的代码块
      	}
      
      注意:前一种方法,锁对象为this;后一种锁对象为类名.class
  3. Lock锁(java.util.concurrent.locks.ReentrantLock
    1. 方法
      1. 加锁:void lock();
      2. 解锁:void unlock();
    2. 使用步骤
      1. Thread子类/Runnable实现类的成员变量常创建ReentrantLock对象
      2. 在可能会出现线程安全的代码前调用lock()加锁
      3. 在可能会出现线程安全的代码执行完成之后调用unlock()解锁(最好将unlock()放入finally,无论代码是否发生异常,都会把锁释放->提高程序效率)

线程状态

在这里插入图片描述

  1. 新建状态
  2. 可运行状态(线程可能正在运行也可能没有运行)
    抢占式调度系统给每个可运行线程一个时间片来执行任务
  3. 阻塞状态
    暂时是不活动的,消耗最少资源。
    当一个线程试图获得一个内部的对象锁,而这个所目前正在被另一线程占用,该线程就会被阻塞。
  4. 计时等待状态
  5. 等待状态
    暂时是不活动的,消耗最少资源
  6. 终止状态

线程通信–等待唤醒机制

多个线程在处理同一资源,并且在任务不同时,需要线程通信来帮助解决线程之间同一资源的操作,
注意:

  1. 线程必须用同步代码块包裹起来,保证等待和环唤醒只有一个执行
  2. 同步使用的锁对象必须唯一
  3. 只有锁对象可以调用wait()notify()
  4. ??调用唤醒方法之后,若没有获得锁,则进入阻塞状态;否则,进入可运行状态:被通知的线程不能立即恢复执行,因为它当初中断的地方是在同步代码块中,而此时它已不持有锁,所以需要再次获取,成功获得锁之后才可以获取继续在wait()之后执行的权力

线程池

可容纳多个线程的容器
好处

  1. 降低资源消耗
  2. 提高响应速度
  3. 提高线程的可管理性

创建
public static ExecutorService ewFixedThreadPool(int nThread)返回Executors实现类对象ExecutorService
使用步骤
1. 使用线程池的工厂类java.util.concurrent.Executors的静态方法newFixedThreadPool(int nThread)生成一个指定线程数量的线程池
2. 创建一个Runnable实现类,重写run()方法,设置线程任务
3. 调用Future submit(Runnable task)传递线程任务

案例分析

需求:顾客告知包子铺要买包子,包子铺在没有包子的情况下花费一定时间做包子,做好包子后,通知顾客可以吃包子。
在这里插入图片描述
分析:
for顾客
1. 有包子:吃包子->修改包子状态“false”->告知包子铺做包子
2. 无包子:等待
for包子铺
1. 无包子:做包子->修改包子状态”true“->通知顾客吃包子
2. 有包子:等待
实现:

  1. 顾客线程类
    任务:判断是否有包子,没有包子,等待;否则,吃包子,设置包子状态,通知包子铺
  2. 包子铺线程类:
    任务:判断是否有包子,有包子,等待;否则,花时间做包子,然后通知顾客可以吃包子了
  3. 包子类(共享数据)
    包子当前的状态:true有,false
  4. 测试类
  • 创建包子类,作为锁对象,传递到两个线程中
  • 创建线程对象,构造函数传递锁对象参数
  • 调用start()开启线程

注意:

  1. 线程任务包裹在同步代码块中,保证顾客线程和包子铺线程只有一个可以操作包子资源
  2. 两个线程使用同一个锁对象,以保证同步
  3. 调用notify()唤醒另一线程后,继续执行wait()后代码,因而,先wait(),后实现线程通信的notify()

写在最后

多线程这部分内容还是不是很理解,之后还要花时间再学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值