初始多线程

文章目录

  • 线程
    • 线程简介
    • 线程和进程的联系和区别
    • 使用Thread实现多线程编程(java)
      • 1. 继承thread类, 重写run:
      • 2. 实现Runnable接口, 重写方法
      • 3. 使用匿名内部类, 继承Thread
      • 4. 创建匿名内部类, 实现Runnable
      • 5. 使用Lambda
    • Thread类
      • 1. 构造函数
      • 2. 常见属性
      • 3. interrupt; 中断线程
      • 4. 线程等待 join();
      • 4. 获取当前线程的引用(类方法)
      • 5. 使线程休眠(类方法)
    • 线程状态
      • 线程状态的转换
        • 以画图形式展示
        • 以代码展示
  • 多线程和单线程的效率区别

线程

计算机获取当前时间戳:System.currentTimeMillis()
IDEA规范代码:`ctrl+ait+l
IDEA同时操作多行: ctrl+ait+t
IDEA导入缺失包: ctrl+ait+o

线程简介

  1. 为了解决并发编程问题, 引入了进程, 但是由于进程在创建, 销毁, 调度时的开销太大(主要是资源分配和释放), 所以又引进了线程
  2. 线程省下了资源分配和释放, 多个线程共用进程中的同一资源(意味着多个线程只需进行一次资源分配, 资源分配以进程为单位, 一个进程包含多个线程)
  3. 一个进程至少包含一个线程, 可以包含多个线程
  4. 线程是系统调度执行的基本单位, 进程是系统资源分配的基本单位, 进程中的第一个线程在启动时是和进程一起启动的, 所以第一个线程在启动时需要申请资源, 但是之后的线程不需要
  5. 在同一个进程中的线程共享的有pid, 内存(线程1new的对象在线程2中也可以使用)和文件描述符表(线程1打开的文件线程2也可以使用)
  6. 一个线程也用PCB来描述, 一个进程中可以有一个PCB, 也可以有多个PCB.
  7. 一个进程中的多个PCB,其pid, 内存指针和文件描述符表一样, 但是他们有各自独立的状态, 优先级, 上下文, 记账信息
  8. 一个核心上执行一个线程
  9. 不是线程越多, 程序执行的越快. 因为cpu的的核心是有限的, 过多的线程不仅不会增加程序运行的速度, 反而会因为频繁的线程调度而变得卡顿
  10. 过多的线程可能会抢占共享的内存资源或者文件描述符集, 造成线程安全问题.同理, 进程间进行通信时, 同时访问到同一资源时, 也会触发进程安全问题
  11. 过多的线程在抢占cpu的过程中落败时,可能会使这个线程崩溃, 而一个线程崩溃会造成整个进程的崩溃

线程和进程的联系和区别

  1. 线程和进程都是为了解决并发编程问题
  2. 线程是系统调度执行的基本单位, 进程是系统资源分配的基本单位,
  3. 线程相比于进程来说, 创建, 销毁, 调度时的开销更小(更轻量)
  4. 进程里包含若干线程, 每个线程被独立调度执行, 一个进程里的若干线程共享进程的内存资源和文件描述表, 每个线程有自己的状态, 优先级, 上下文, 记账信息

使用Thread实现多线程编程(java)

在进行多线程编程时, 是依靠java的JVM来进行的, 操作系统给java的JVM提供api, JVM将这些api封装之后再给程序员提供api. 不同的操作系统上安装不同的JVM, JVM提供给适配当前系统的api. 使得相同的字节码文件能在不同的操作系统上运行, 从而实现跨平台编程

1. 继承thread类, 重写run:

thread用于创建线程变量, 一个thread对象对应一个PCB

class MyThread extends Thread{
   
    public void run(){
   
        while(true){
   
            System.out.println("线程1");
            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   
                throw new RuntimeException(e);
            }
        }
    }
}

public class ThreadDome1 {
   
    public static void main(String[] args) throws InterruptedException {
   
        Thread t = new MyThread();   //创建线程变量
        t.start();
        while(true){
   
            System.out.println("线程2");
            Thread.sleep(1000);
        }
    }
}

代码解读:

  1. 如果不使用Thread, 直接在main函数中打印输出, 那么就是一个进程中只有一个线程(main线程), 此线程称为主线程
  2. 加入了Thread之后, start是操作系统提供的api, 主线程通过调用start函数, 使操作系统来创建一个新的PCB, 并把指令提供给此PCB, 此PCB被调用到CPU上时, 就会执行run方法, 从而实现多线程, 以上代码会轮流打印线程1和2.
    初始多线程_第1张图片
  3. start与run的区别:
    (1)start 是让操作系统去创建一个新的PCB
    (2)run是描述这个PCB要去执行什么, 如果在程序中直接写run, 不用start, 那么就只有一个main主线程, 这个线程在不停的打印线程1, 线程2无法打印

2. 实现Runnable接口, 重写方法

class MyRunable implements Runnable{
   

    @Override
    public void run() {
   
        while(true){
   
            System.out.println("线程1");
            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   

            }
        }
    }
}
public class ThreadDome2 {
   
    public static void main(String[] args) throws InterruptedException {
   
        MyRunable runable = new MyRunable();
        Thread thread = new Thread(runable);
        thread.start();
        while(true){
   
            System.out.println("线程2");
            Thread.sleep(1000);
        }
    }
}

3. 使用匿名内部类, 继承Thread

        Thread t = new Thread(){
   
            public void run(){
   
                while(true){
   
                    out.println("线程1");
                    try {
   
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
   
                        throw new RuntimeException(e);
                    }
                }
            }
        };

在上面代码中的Thread t = new Thread(){}, 做了两件事情,
第一是创建了一个Thread的子类, 这个子类没有名字
第二是创建了子类的实例, t引用了这个实例

import 

你可能感兴趣的:(操作系统,java,jvm,linux)