Java 多线程学习 一

概述:

这里写图片描述

1. 进程和多线程介绍:

简单来说:
  • 进程 : 启动一个xxx.exe, 这叫一个进程
  • 线程 : 线程是进程内部同时做的事
  • 多线程 : 多线程就是多个线程同时运行或交替运行。单核 CPU 的话是顺序执行,也就是交替运行。多核 CPU 的话,因为每个 CPU 有自己的运算器,所以在多个 CPU 中可以同时运行。
为什么需要多线程:
  1. 使用线程可以把占据长时间的程序中的任务放到后台去处理
  2. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  3. 程序的运行速度可能加快

2. 如何使用多线程

1. 继承Thread: 重写run()方法
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("MY THREAD");
    }
}
2. 实现Runnable接口, 重写run()方法
  • 推荐使用这个办法实现多线程, 因为Java只能单继承, 但是可以实现多个接口
public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("My Runnable");
    }
}
测试代码:
public class ThreadTest {
    public static void main(String[] args) {

        //继承Thread的多线程
        MyThread thread1 = new MyThread();
        thread1.start();

        System.out.println("运行结束");

        //"运行结束"先出来, 说明cpu随机调用run方法

        System.out.println("==========================================================");

        //实现Runnable接口的多线程
        Runnable runnable = new MyRunnable();
        Thread thread2 = new Thread(runnable);
        thread2.start();
        System.out.println("运行结束");

    }
}
运行结果: 说明cpu执行run方法时随机的

运行结束
MY THREAD
==========================================================
运行结束
My Runnable

3. 实例变量和线程安全

· 定义线程类中的实例变量针对其他线程有共享和不共享之分
不共享的情况:
1. 不共享数据
public class ThreadNotShareData extends Thread {
    private int count = 5;

    //定义线程名字
    public ThreadNotShareData(String name){
        super();
        this.setName(name);
    }

    @Override
    public void run() {
        super.run();
        while (count > 0){
            count --;
            System.out.println("由 " + ThreadNotShareData.currentThread().getName() + " 计算, count = "+ count);
        }
    }
}
2. 共享数据的情况
public class ThreadShareData extends Thread {
    private int count = 6;

    @Override
    synchronized public void run() {
        super.run();
        count --;
        System.out.println("由 " + ThreadNotShareData.currentThread().getName() + " 计算, count = "+ count);
    }
}
测试类:
public class DataShareTest {
    public static void main(String[] args) {

        //数据不共享的情况
//        ThreadNotShareData a = new ThreadNotShareData("a");
//        ThreadNotShareData b = new ThreadNotShareData("b");
//        ThreadNotShareData c = new ThreadNotShareData("c");
//
//        a.start();
//        b.start();
//        c.start();
        //结果看出每个线程都有一个自己的count, 互不影响


        //数据共享情况
        ThreadShareData thread = new ThreadShareData();
        //以下线程都是 ThreadShareData 对象创建的
        Thread d = new Thread(thread, "d");
        Thread e = new Thread(thread, "e");
        Thread f = new Thread(thread, "f");
        Thread g = new Thread(thread, "g");
        Thread h = new Thread(thread, "h");

        d.start();
        e.start();
        f.start();
        g.start();
        h.start();
        //count是Thread对象的属性, 其他线程都是操作thread的count属性, 会造成混乱

        //在run方法前面加synchronized关键字就可以得到正确答案, 加锁

    }
}

4. 线程类常用方法

  1. currentThread()
    返回对当前正在执行的线程对象的引用。
  2. getId()
    返回此线程的标识符
  3. getName()
    返回此线程的名称
  4. getPriority()
    返回此线程的优先级
  5. isAlive()
    测试这个线程是否还处于活动状态。
    • 什么是活动状态呢?
    • 活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备运行的状态。
  6. sleep(long millis)
    使当前正在执行的线程以指定的毫秒数 “休眠”(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
  7. interrupt()
    中断这个线程。
  8. interrupted() 和 isInterrupted()

    • interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志清除为 false 的功能
    • isInterrupted(): 测试线程 Thread 对相关是否已经是中断状态,但部清楚状态标志
  9. setName(String name)
    将此线程的名称更改为等于参数 name 。

  10. isDaemon()
    测试这个线程是否是守护线程。

  11. setDaemon(boolean on)
    将此线程标记为 daemon 线程或用户线程。

  12. join()
    在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到 join() 方法了。
    join() 的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了 join() 方法后面的代码,只有等到子线程结束了才能执行

  13. yield()
    yield() 方法的作用是放弃当前的 CPU 资源,将它让给其他的任务去占用 CPU 时间。注意:放弃的时间不确定,可能一会就会重新获得 CPU 时间片。
  14. setPriority(int newPriority)
    更改此线程的优先级

5. 如何停止一个线程

1. 三个弃用的方法:

这里写图片描述

2. 停止线程: 在后面介绍

6. 线程优先级

  1. 每个线程都具有各自的优先级,线程的优先级可以在程序中表明该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这个并不意味着低 优先级的线程得不到运行,而只是它运行的几率比较小,如垃圾回收机制线程的优先级就比较低。所以很多垃圾得不到及时的回收处理。
  2. 线程优先级具有继承特性比如 A 线程启动 B 线程,则 B 线程的优先级和 A 是一样的。
  3. 线程优先级具有随机性也就是说线程优先级高的不一定每一次都先执行完。
  4. Thread 类中包含的成员变量代表了线程的某些优先级。如
    1. Thread.MIN_PRIORITY(常数 1),Thread.NORM_PRIORITY(常数 5),
      Thread.MAX_PRIORITY(常数10)。
    2. 其中每个线程的优先级都在Thread.MIN_PRIORITY(常数1)到 Thread.MAX_PRIORITY(常数10)之间,
    3. 在默认情况下优先级都是 Thread.NORM_PRIORITY(常数 5)。

7. Java多线程分类

  • 用户线程:运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用户线程

  • 守护线程:运行在后台,为其他前台线程服务. 也可以说守护线程是 JVM 中非守护线程的 “佣人”。

  • 特点:一旦所有用户线程都结束运行,守护线程会随 JVM 一起结束工作

  • 应用:数据库连接池中的检测线程,JVM 虚拟机启动后的检测线程

  • 最常见的守护线程:垃圾回收线程

如何设置守护线程: 调用Thead 类的 setDaemon(true) 方法

  1. setDaemon(true)必须在start()方法前执行,否则会抛出IllegalThreadStateException异常
  2. 在守护线程中产生的新线程也是守护线程
  3. 不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值