初阶_多线程1(线程含义与关键属性)

多线程

································································

一、线程

1.什么是线程

一个线程是一个执行流,每个线程都可以按顺序执行自己的代码,多个线程"同时"执行自己的代码。

2.为什么要有线程

创建销毁进程的开销大,尤其是频繁操作,引入线程,创建销毁开销更加小更加快

3.进程与线程的关系与区别

1.进程包含线程 ,每个进程都有一个或者多个线程

2.进程与进程之间不共享资源 ,进程是操作系统资源分配的基本单位,而线程与线程之间共享资源 ,所以当一个进程崩溃不会影响其他进程 ,但是一个线程挂了可能其他线程(整个进程)都崩溃 (这就是线程安全相关问题及时捕获可能不会崩溃)

3.线程是CPU上调度执行的最小单位 ,如果一个线程包含多个进程,此时多个进程各自去cpu上调度执行

4.一个进程中的线程共用一个文件描述符表和内存指针,但是每个线程都有自己的调度相关的(状态、优先级、上下文、记账信息),一个进程并不是越多越好,过多线程产生的调度开销也很大,会拖慢程序的性能

4.创建线程

对于线程,操作系统提供一些api(应用程序编程接口)给程序员使用,操作系统提供的原生线程api是c语言的,而且不同操作系统的线程api不同,java对上述内容进行统一封装,如Thread类(标准库中提供的类)。
方法1:继承Thread类创建一个线程类

java 复制代码
class Mythread extends Thread{
    @Override
    public void run() {
        while(true) {
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class demo1 {
    public static void main(String[] args) {
      Mythread mythread=new Mythread();
      //start方法创建一个线程,多一个执行流,像是多一个人干活
      mythread.start();
      while (true) {
          try {
          //sleep静态方法让当前线程暂时放弃CPU,过1000毫秒后继续执行
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              throw new RuntimeException(e);
          }
          System.out.println("hello main");
      }
    }
}

运行结果显示有时候先输出main有时先输出thread,这是因为多个线程的调度顺序是随机的,无法预测(唯一可以做的就是设置优先级,但是对于操作系统也不一定严格执行。

方法2:实现Runnable接口

java 复制代码
class MyRunnable implements Runnable {
    @Override
    public void run() {
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class demo2 {
    public static void main(String[] args) {
       MyRunnable runnable=new MyRunnable();
       Thread thread=new Thread(runnable);
       thread.start();
       while (true){
           System.out.println("hello main");
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
       }
    }
}

方法3:使用内部类操作方法1

java 复制代码
public class demo3 {
    public static void main(String[] args) {
        Thread thread=new Thread(){
            @Override
            public void run() {
                while (true){
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        thread.start();
        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

对于匿名内部类:

Thread thread=new Thread(){};

1.创建一个Thread的子类,子类匿名

2.{}中写子类的属性,方法

3.创建匿名内部类的实例,并且把实例赋值给thread

方法4:使用内部类操作方法2

java 复制代码
public class demo4 {
    public static void main(String[] args) {
        Runnable runnable=new Runnable(){
            @Override
            public void run() {
                while (true){
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        Thread t=new Thread(runnable);
        t.start();
        while (true){
            System.out.println("hello main" +
                    "");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

}

方法5:使用lambda表达式创建Runnable子类对象

java 复制代码
public class demo5 {
    public static void main(String[] args) {
        Thread thread=new Thread(()->{
            while (true){
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"t1");
        thread.start();
        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

lambda("匿名函数")(主要需要方法但必须依托类存在使用"函数式接口"简化代码)

()-> 创建一个匿名的函数式接口的子类,并且创建出对应实例重写方法

  • lambda访问外部变量的限制

如果把在lambda中使用的变量,定义成局部变量是否可以?

如果要把变量定义成局部变量,则这个变量不能修改,或者直接设置成final 。这是由于变量捕获 ,因为lambda是回调函数,系统创建线程后才会执行,可能当main主线程执行完局部变量都销毁了,而lambda还需要使用,所以java会把变量拷贝一份到lambda里面 ,这样即使外面变量销毁也不影响lambda里面使用,而拷贝也就意味着变量不能进行修改 。如果这个局部变量是个引用类型,那么这个引用本身不可以修改 ,不能指向其它对象,而对象本体是可以修改的,因为对象本体是JVM垃圾回收机制管理,不会随着main函数结束而销毁。
如果是成员变量呢?

将变量改为成员变量,就不会报错,因为此时不再是"变量捕获"语法,而是"内部类访问外部类的成员 "语法。
lambda本质是一个函数式接口,相当于一个内部类,isFinished就是外部类的成员,内部类本身就可以访问外部类的成员,成员
变量生命周期是由垃圾回收GC管理的
,所以lambda不用担心销毁,就不必拷贝,就可以修改了。

5.线程构造方法与属性

Java Thread 常见构造方法

构造方法签名 方法说明 核心参数解释
Thread() (方法1) 创建一个新的线程对象,线程名称为默认格式(如Thread-0),无目标任务,需重写run()方法 无参数
Thread(Runnable target)(方法2) 创建一个新线程,将Runnable接口的实现类作为线程执行的目标任务 target:实现了Runnable接口的对象,线程启动后会执行该对象的run()方法
Thread(String name) 创建指定名称的线程对象,便于调试和日志排查,无目标任务 name:自定义的线程名称(如"业务处理线程-1"
Thread(Runnable target, String name) (方法5) 创建指定目标任务且指定名称的线程(最常用的构造方法之一) target:线程执行的任务;name:线程自定义名称
Thread(ThreadGroup group, Runnable target)(了解) 将线程归属到指定的线程组,并指定执行任务 group:线程所属的ThreadGroup(用于批量管理线程);target:执行任务

常见属性

属性(获取方法) 数据类型 属性说明
getId() long 获取线程的唯一ID
getName() / setName(String name) String 获取/设置线程名称
getPriority() / setPriority(int newPriority) int 获取/设置线程优先级
getState() Thread.State 获取线程状态
isDaemon() / setDaemon(boolean on) boolean 判断/设置是否为守护线程
isAlive() boolean 判断线程是否存活
isInterrupted() boolean 判断线程是否被中断
interrupted()(静态方法) boolean 判断当前线程是否被中断

重点属性
1)后台线程

| isDaemon() / setDaemon(boolean on) | boolean |

判断/设置是否为守护线程(后台进程)

前台进程例如我们自己创建的线程包括main主线程,但我们可以通过setDaemon方法将它改为后台线程 ,后台进程例如JVM自带的具有特殊功能的线程,跟随整个进程持续执行。JVM会在一个进程的所有前台线程结束后才结束运行,而后台线程对结束无影响

2)是否存活(简单理解为run方法运行结束)

| isAlive() | boolean | 判断线程是否存活 |

java中创建的Thread对象与系统的线程一一对应,但是两者的生命周期并不相同,可能Thread对象依然存在但是对应的系统的线程已经销毁

上面for循环执行完对象thread可能依然存在
3)启动一个线程start方法

每个Thread对象,start是一次性的 ,进行调用系统的api,每次创建新线程,都得创建一个新的Thread对象。
4)中断一个线程isInterrupted()

中断即线程停止不会再恢复

lambda的定义在new Tread之前,所以不能直接在里面使用,但是java的Thread对象中提供了现成的变量,我们可以使用Thread.currentThread()静态方法,哪个线程中调用,获取的就是哪个线程的Thread引用

相关推荐
程序媛徐师姐4 小时前
Java基于微信小程序的模拟考试系统,附源码+文档说明
java·微信小程序·java模拟考试系统小程序·模拟考试微信小程序·模拟考试系统小程序·模拟考试小程序·java模拟考试小程序
疯狂敲代码的老刘5 小时前
JDK 1.6到25 全版本网盘合集 (Windows + Mac + Linux)
java·linux·windows·macos·jdk
夕除5 小时前
js--15
java·jvm·spring
曾经的三心草5 小时前
redis-9-集群
java·redis·mybatis
sun03225 小时前
【架构基础】Spring中的PropertySourcesPlaceholderConfigurer介绍 (并非新知识,比较古老的一种使用方式)
java·spring·架构
chilavert3185 小时前
技术演进中的开发沉思-356:重排序(中)
java·开发语言
毕设源码-邱学长5 小时前
【开题答辩全过程】以 基于SSM的儿童福利院管理系统为例,包含答辩的问题和答案
java·eclipse
TT哇5 小时前
【实习】数字营销系统 银行经理端(interact_bank)前端 Vue 移动端页面的 UI 重构与优化
java·前端·vue.js·ui
Elieal5 小时前
SpringBoot 数据层开发与企业信息管理系统实战
java·spring boot·后端