• (十四)线程(基础)


    一、线程基本使用 

    1. 创建线程的两种方式

    (1)继承 Thread 类,重写run方法
    (2)实现 Runnable 接口,重写run方法

    2. 线程应用案例1-继承Thread类

    1. public class Thread01 {
    2. public static void main(String[] args) {
    3. Cat cat = new Cat();
    4. cat.start();
    5. }
    6. }
    7. class Cat extends Thread{
    8. @Override
    9. public void run() {
    10. while (true){
    11. System.out.println("miaomiao");
    12. try {
    13. Thread.sleep(1000);
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. }
    19. }

    3. 线程应用案例2-实现Runnable接口

    (1)java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承 Thread 类方法来创建线程显然不可能了
    (2)java设计者们提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程

    1. public class Thread02 {
    2. public static void main(String[] args) {
    3. Dog dog = new Dog();
    4. Thread thread = new Thread(dog);
    5. thread.start();
    6. }
    7. }
    8. class Dog implements Runnable {
    9. @Override
    10. public void run() {
    11. while (true) {
    12. System.out.println("wangwang");
    13. try {
    14. Thread.sleep(1000);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. }
    20. }

    4. 继承Threadvs实现Runable的区别

    (1)从 java 的设计来看,通过继承 Thread 或者实现 Runnable 接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到 Thread 类本身就实现了 Runnable 接口
    (2)实现 Runnable 接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制

    1. public class Thread03 {
    2. public static void main(String[] args) {
    3. T3 t3 = new T3();
    4. Thread thread1 = new Thread(t3);
    5. Thread thread2 = new Thread(t3);
    6. thread1.start();
    7. thread2.start();
    8. }
    9. }
    10. class T3 implements Runnable{
    11. @Override
    12. public void run() {
    13. }
    14. }

    二、线程终止

    (1)当线程完成任务后,会自动退出
    (2)还可以通过使用变量来控制 run 方法退出的方式停止线程,即通知方式

    1. public class ThreadExit_ {
    2. public static void main(String[] args) throws InterruptedException {
    3. T t1 = new T();
    4. t1.start();
    5. Thread.sleep(10*1000);
    6. t1.setLoop(false);
    7. }
    8. }
    9. class T extends Thread{
    10. private boolean loop = true;
    11. @Override
    12. public void run() {
    13. while (loop){
    14. try {
    15. Thread.sleep(50);
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. System.out.println("T 运行中");
    20. }
    21. }
    22. public void setLoop(boolean loop) {
    23. this.loop = loop;
    24. }
    25. }

    三、线程常用方法

    (1)setName        //设置线程名称
    (2)getName        //返回该线程的名称
    (3)start        //使该线程开始执行:Java虚拟机底层调用该线程的 start0 方法
    (4)run        //调用线程对象run方法
    (5)setPriority        //更改线程的优先级
    (6)getPriority        //获取线程的优先级
    (7)sleep        //在指定的毫秒数内让当前正在执行的线程休眠民(暂停执行)
    (8)interrupt        //中断线程

    1. public class ThreadMethod {
    2. public static void main(String[] args) {
    3. T t = new T();
    4. t.setName("线程1");
    5. t.setPriority(Thread.MAX_PRIORITY);
    6. t.start();
    7. t.interrupt();
    8. System.out.println(t.getPriority());
    9. }
    10. }
    11. class T extends Thread {
    12. @Override
    13. public void run() {
    14. System.out.println(Thread.currentThread().getName());
    15. while (true) {
    16. for (int i = 0; i < 10; i++) {
    17. System.out.println("任务执行中" + i);
    18. }
    19. try {
    20. Thread.sleep(2000);
    21. } catch (InterruptedException e) {
    22. // 当该线程执行了 interrupt 方法时,就会catch异常。这时可以加入自己的业务代码
    23. // InterruptedException 捕获到了一个中断异常
    24. System.out.println("被 interrupt了,业务执行中");
    25. }
    26. }
    27. }
    28. }

    注意:

    ①start:底层会创建新的线程,调用 run,run 就是一个简单的方法调用,不会启动新
    线程

    ②interrupt:中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线程

    (9)yield:线程的礼让。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功

    (10)join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

    四、用户线程和守护线程

    (1)用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
    (2)守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
    (3)常见的守护线程:垃圾回收机制

    1. public static void main(String[] args) {
    2. T t = new T();
    3. t.setDaemon(true);
    4. t.start();
    5. }

    五、线程生命周期

    Thread.State 枚举类

    (1)NEW:尚未启动的线程处于此状态

    (2)RUNNABLE:在 Java 虚拟机中执行的线程处于此状态

    (3)BLOCKED:被阻塞等待监视器锁定的线程处于此状态

    (4)WAITING:正在等待另一个线程执行特定动作的线程处于此状态

    (5)TIMED WAITING:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态

    (6)TERMINATED:已退出的线程处于此状态

    六、线程的同步

    1. 互斥锁(synchronized

    (1)Java语言中,引入了对象互序锁的概念,来保证共享数据操作的完整性

    (2)每个对象都对应于一个可称为“互序锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象

    (3)关键字 synchronized 来与对象的互斤锁联系。当某个对象用 synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问

    (4)同步的局限性:导致程序的执行效率要降低

    (5)同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)

    (6)同步方法(静态的)的锁为当前类本身

    注意事项和细节:

    (1)同步方法如果没有使用 static 修饰:默认锁对象为 this

    (2)如果方法使用 static 修饰,默认锁对象:当前类.class

    (3)实现的落地步骤:

    ①需要先分析上锁的代码

    ②选择同步代码块(优先选择)或同步方法

    ③要求多个线程的锁对象为同一个即可

    2. 死锁

    多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程是一定要避免死锁的发生

    3. 释放锁

    (1)当前线程的同步方法、同步代码块执行结束
    案例:上厕所,完事出来

    (2)当前线程在同步代码块、同步方法中遇到break、return。
    案例:没有正常的完事,经理叫他修改bug,不得已出来

    (3)当前线程在同步代码块、同步方法中出现了未处理的 Error 或 Exception,导致异常结束
    案例:没有正常的完事,发现忘带纸,不得已出来

    (4)当前线程在同步代码块、同步方法中执行了线程对象的 wait() 方法当前线程暂停,并释
    放锁。
    案例:没有正常完事,觉得需要际酿下,所以出来等会再进去

    3.2 下面操作不会释放锁

    (1)线程执行同步代码块或同步方法时,程序调用 Thread.sleep()、Thread.yield() 方
    法暂停当前线程的执行,不会释放锁
    案例:上厕所,太困了,在坑位上睡了一会

    (2)线程执行同步代码块时,其他线程调用了该线程的 suspend() 方法将该线程挂起
    该线程不会释放锁
    提示:应尽量避免使用 suspend() 和 resume() 来控制线程,方法不再推荐使用

  • 相关阅读:
    java版直播商城平台规划及常见的营销模式 电商源码/小程序/三级分销+商城免费搭建
    0143__c++filt(1) command
    数据中台的前世今生(一):数据仓库——数据应用需求的涌现
    MySQL(18):MySQL8.0的其它新特性
    外贸万圣灯饰、南瓜灯具美国站UL588测试项目
    MATLAB算法实战应用案例精讲-【智能优化算法】蛇优化算法-SO(附MATLAB代码)
    【星海出品】C++类的学习(通过代码)
    python 移动测试之Appium环境搭建及简单应用
    wpf 命令概述
    计算机毕业设计Java超市管理系统(源码+系统+mysql数据库+lw文档)
  • 原文地址:https://blog.csdn.net/yirenyuan/article/details/126393009