Java多线程基础

2021/12/20 20:21:38

本文主要是介绍Java多线程基础,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java多线程基础

  • 进程和多线程
  • 创建多线程
    • 继承Thread类
      • 分析线程信息
    • 实现Runnable接口
  • 线程安全问题
  • 常用方法
    • currentThread()
    • isAlive()
    • sleep(long millis)
    • sleep(long millis,int nanos)
    • StackTranceElement[ ] getStackTrace()
    • static void dumpStack()
    • getID()
  • 停止线程
    • interrupt() 方法
    • 判断线程是否停止
    • interrupt()方法中断线程
    • 使用stop() 方法暴力停止线程(不推荐)
  • 暂停线程
  • yield方法
  • 线程优先级
  • 守护线程

进程和多线程

进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。
程序:指令序列,用来让cpu完成指定的任务,一个.java程序经过编译形成.class文件,操作系统创建一个JVM虚拟机进程(每执行一次main方法就创建一个JVM进程),并在虚拟机中加载class文件并运行,进程通过创建你新线程来执行具体的任务。
线程:线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

创建多线程

继承Thread类

在这里插入图片描述

分析线程信息

使用jdk中的命令分析线程信息

  1. jps+jstack.ext
  2. jmc.exe
  3. jvisualvm.exe

实现Runnable接口

在这里插入图片描述
Thread.java类的8个构造方法
在这里插入图片描述

  • Thread()
    分配一个新的 Thread对象。
  • Thread(Runnable target)
    分配一个新的 Thread对象。
  • Thread(Runnable target, String name)
    分配一个新的 Thread对象。
  • Thread(String name)
    分配一个新的 Thread对象。

构造函数Thread(Runnable target) 不仅可以传入Runnable接口对象,而且可以传入一个Thread类的对象。

线程安全问题

在这里插入图片描述
在这里插入图片描述
在run()方法前添加synchronized关键字,一个线程调用run方法前会判断run方法有没有上锁,如果run方法被上锁,说明其他线程正在调用,必须等待。
synchronized可以对任意对象及方法加锁,被加锁的这段代码称为“互斥区”或“临界区”。
在这里插入图片描述
在这里插入图片描述

常用方法

currentThread()

返回代码正在被哪个线程调用
在这里插入图片描述
在这里插入图片描述
run2的构造函数是被main线程调用,run方法是被Thread-0的线程调用
在这里插入图片描述
执行方法run()和start()方法的区别:

  1. run方法:立即执行run方法,不启动新线程。
  2. start方法:执行run方法的时机不确定,启动新线程。

isAlive()

isAlive方法判断当前线程是否存活
在这里插入图片描述

sleep(long millis)

在指定的时间(毫秒)内让当前正在执行的线程休眠,这个当前正在执行的线程是指this.currentThread()返回的线程。
在这里插入图片描述

sleep(long millis,int nanos)

在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠
在这里插入图片描述

StackTranceElement[ ] getStackTrace()

作用是返回一个表示该线程堆栈跟踪元素数组

static void dumpStack()

将当前线程的堆栈跟踪信息输出到标准错误流

getID()

用于取得线程的唯一标识
在这里插入图片描述

停止线程

interrupt() 方法

调用interrupt方法仅仅在当前线程中做了一个停止的标记,并不是真正的停止线程
在这里插入图片描述

判断线程是否停止

  • public static boolean interrupted() :测试currentThread()是否已经中断,执行后具有清除状态标志值为false的功能。也可以用Thread.interrupted()判断,因为在Thread.java类中调用静态static方法时,大多数是针对currentThread()线程进行操作的
  • public boolean this.isIntererupted() :测试this关键字所在类的对象是否已经中断,非静态方法,作用与调用这个方法的对象。不清楚状态标志。

interrupt()方法中断线程

public class MyThread5 extends Thread {
    @Override
    public void run() {
        super.run();
        try{
            for (int i = 0; i <500000 ; i++) {
                if(this.isInterrupted()){
                    System.out.println("已经是停止状态,我要推出了!");
                    throw new InterruptedException();
                    //或者不抛异常,直接return
                }
                System.out.println("i="+(i+1));
            }
        }
        catch (InterruptedException e){
            System.out.println("进入run方法中的catch了!!");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try{
            MyThread5 myThread5 = new MyThread5();
            myThread5.start();
            Thread.sleep(2000);
            myThread5.interrupt();
        } catch (InterruptedException e) {
            System.out.println("main catch!!");
            e.printStackTrace();
        }
        System.out.println("end!!!");
    }
}


sleep和interrupt
不管调用顺序,只要interrupt()和sleep()方法碰到一起就会出现异常:在sleep状态执行interrupt()方法会出现异常;调用interrupt()方法给线程打上了中断标记,在执行sleep()方法也会出现异常

使用stop() 方法暴力停止线程(不推荐)

public class MyThread6 extends Thread {
    private int i=0;
    @Override
    public void run() {
        super.run();
        try {
            while (true){
                i++;
                System.out.println("i="+i);
                Thread.sleep(1000);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread6 myThread6 = new MyThread6();
        myThread6.start();
        Thread.sleep(8000);
        myThread6.stop();
    }
}

在这里插入图片描述

暂停线程

在Java多线程中,可以使用suspend()方法暂停线程,使用resume()方法来恢复线程的执行
在这里插入图片描述
suspend()、resume() 方法是过期作废的方法,原因是容易造成公共同步对象被独占,其他线程无法访问公共同步对象的结果,因此想要实现对线程进行暂停与恢复的处理,可以使用wait()、notify()或者notifyAll()方法
System.out.println也是同步方法

yield方法

yield方法的作用是放弃当前的cpu资源,让其他任务去占用cpu执行时间,放弃的时间不确定,有可能刚刚放弃,马上又获得cpu时间片
在这里插入图片描述

线程优先级

在Java中线程的优先级分为1-10共10个等级,如果线程优先级小于1或者大于10,则JDK抛出异常 throw new IllegalArguementException()

  1. 线程优先级的继承特性
    在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级和A线程的优先级是一样的
public class MyThread10 extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread10 run priority="+this.getPriority());
    }
}
public class MyThread9 extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread9 run priority="+this.getPriority());
        MyThread10 myThread10 = new MyThread10();
        myThread10.start();
    }

    public static void main(String[] args) {
        System.out.println("main thread begin priority="+Thread.currentThread().getPriority());
        //Thread.currentThread().setPriority(6);
        System.out.println("main thread end priority="+Thread.currentThread().getPriority());
        MyThread9 myThread9 = new MyThread9();
        myThread9.start();
    }
}

在这里插入图片描述
去掉注释
在这里插入图片描述
2. 优先级的规律
高优先级的线程总是大部分先执行完,但不代表高优先级的线程全部先执行完,CPU尽量将执行资源让给优先级比较高的线程,线程的优先级与执行顺序具有不确定性、随机性

守护线程

Java中有两种线程,一种是用户线程,另一种是守护线程
守护线程是一种特殊线程,当进程中不存在用户线程了,则守护线程自动销毁,典型的守护线程是垃圾回收线程
只用当最后一个用户线程结束时,则守护线程才随着JVM一同结束,守护线程的作用是为其他运行的线程提供服务。

public class MyThread11 extends Thread {
    private int i=0;

    @Override
    public void run() {
        super.run();
        try{
            while(true){
                i++;
                System.out.println("i="+(i+1));
                Thread.sleep(1000);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try{
            MyThread11 myThread11 = new MyThread11();
            myThread11.setDaemon(true);
            myThread11.start();
            Thread.sleep(5000);
            System.out.println("main 结束,守护线程也随之结束!");
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述



这篇关于Java多线程基础的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程