Java多线程(课堂笔记)

Process与Thread

◆线程就是独立的执行路径;
◆在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程
◆main()称之为主线程,为系统的入口,用于执行整个程序; .
◆在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与
操作系统紧密相关的,先后顺序是不能认为的干预的。
◆对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
◆线程会带来额外的开销,如cpu调度时间,并发控制开销。
◆每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

在这里插入图片描述

Java多线程

  • 程序、进程、线程的概念

  • Java中多线程的创建和使用

    • 继承Thread类与实现Runnable接口
    • Thread类的主要方法
    • 线程的调度与设置优先级周
  • 线程的生命周期

  • 线程的同步

  • 线程的通信

一、基本概念

程序-进程-线程

  • 程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(process)是程序的一次执行过程,或是正在运行的一个程序。动态过程:有它自身的产生存在和消亡的过程。
    • 如:运行中的QQ,运行中的MP3播放器
    • 程序是静态的,进程是动态的
  • 线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径
    • 若一个程序 可同一时间执行多个线程,就是支持多线程的

二、多线程的创建和启动

//创建多线程的第一种方式:一.继承java.lang.Thread类

  • Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来实现。
  • Thread类的特性
    • 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
    • 通过Thread对象的start()方法来调用这个线程
package Thread01;

//创建一个子线程,完成1-100自然数的输出。同样的,主线程执行同样的操作
//创建多线程的第一种方式:一.继承java.lang.Thread类

//1.创建一个继承于Thread的子类
class SubThread extends Thread{
    //2.重写Thread类的run()方法,方法内实现此子线程要完成的功能
    @Override
    public void run() {
        for (int i = 1; i <=100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        //3.创建一个子类对象
        SubThread subThread1 = new SubThread();
        SubThread subThread2 = new SubThread();
        //4.调用线程的start()方法,启动此线程:调用相应的run()方法
        subThread1.start();
        subThread2.start();

//        subThread.start();
//      一个线程只能执行一次start()

//        subThread.run();
//      不能通过Thread实现类对象run()去启动一个线程
        for (int i = 1; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

在这里插入图片描述

三、线程的调度

  • 调度策略

    • 时间片在这里插入图片描述
    • 抢占式:高优先级的线程抢占CPU
  • Java的调度方法

    • 同优先级线程组成先进先出队列(先来先服务),使用时间片策略
    • 对高优先级,使用优先调度的抢占式策略
  • 线程的优先级控制

    • MAX_PRIORITY(10);
    • MIN_PRIORITY(1);
    • NORM_PRIORITY(5);
    • 涉及的方法
      • getPriority():返回线程优先值
      • setPriority(int newPriority):改变线程的优先级
      • 线程创建时继承父线程的优先级
package Thread02;
/*
* Thread常用方法
* 1.start(),启动线程并执行相应的run()方法
* 2.run():子线程要执行的代码放入run()方法中
* 3.currentThread(),静态的,调取当前的线程
* 4.getName():获取此线程的名字
* 5.setName():设置此线程的名字
* 6.yield():调用此方法的线程释放当前CPU的执行权
* 7.join():在A线程中调用B线程的join方法.表示,
* 当执行到此方法,A线程停止执行,直至B线程执行完毕,
* A线程再接着join()之后的代码执行
* 8.isAlive():判断当前线程是否还存活
* 9.sleep(long l):显式的让当前线程睡眠l毫秒
* 10.线程通信:wait()   notify()  notifyAll()
*
* 设置线程的优先级
* - getPriority():返回线程优先值
* - setPriority(int newPriority):改变线程的优先级
* //优先级增加抢占CPU的概率
* */

class SubThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <=100; i++) {
//            try {
//                Thread.currentThread().sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
        }
    }
}
public class TestThread {
    public static void main(String[] args) {
        SubThread subThread = new SubThread();
        subThread.setName("子线程1");
//        subThread.setPriority(10);
        subThread.setPriority(Thread.MAX_PRIORITY);
        subThread.start();
        Thread.currentThread().setName("====主线程");
        for (int i = 1; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
//            if (i%10==0){
//                Thread.currentThread().yield();
//            }
//            if (i==20){
//                try {
//                    subThread.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
        }
        System.out.println(subThread.isAlive());
    }
}

四、实现方式二

package Thread02;
/*
* //创建多线程的方式二,通过实现的方式
*
* 对比一下继承的方式 VS 实现的方式
* 1.联系,public class Thread implements Runnable
* 2.哪个方式好?  实现的方式优于继承的方式
*   为什么 why?
* ①避免了java单继承的局限性
* ②如果多线程要操作同一份资源(或数据),更适合使用实现的方式
* */
//1.创建一个实现了Runnable接口的类
class PrintNum1 implements Runnable{
//2.实现接口的抽象方法
    @Override
    public void run() {
        //子线程执行的代码
        for (int i = 1; i <=100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class TestThread1 {
    public static void main(String[] args) {
        //3.创建一个Runnable接口实现类的对象
        PrintNum1 printNum1 = new PrintNum1();
//        printNum1.start();//无此方法
//        printNum1.run();//不是多线程
        //要想启动一个多线程,必须调用start()
        //4.将此对象作为形参传递给Thread类的构造器中,创建Thread类的对象此对象即为一个线程
        Thread thread = new Thread(printNum1);
        //5.调用start()方法,启动线程并执行run()方法
        thread.start();//启动线程,执行Thread对象生成时构造器形参的对象的run()方法

        //再创建一个线程
        Thread thread1 = new Thread(printNum1);
        thread1.start();
    }
}

五、使用多线程的优点

  1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验
  2. 提高计算机系统CPU的利用率
  3. 改善程序结构。将即长又复制的进程分为多个下次,独立运行,利于理解和修改

生命周期五种状态:

新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态

就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片

此时它已具备了运行条件

运行:当就绪的线程被调度并获得处理器资源时。便进入运行状态,run()方法定义了线程的操作和功能

阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU
并临时中止自己的执行,进入阻塞状态

死亡:线程完成了它的全部工作或线程被提前强制性地中止

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章