多线程基础

发布时间:2024年01月14日

线程运行原理

栈帧图解

栈与栈帧

  • JVM是由堆、栈、方法区所组成,栈的内存是给线程用的。
  • 每个线程启动后,虚拟机就会为其分配一块栈内存
  • 每个栈由多个栈帧(方法)组成,对应着每个方法调用时所占用的内存。
  • 每个线程只能有一个活动栈帧。对应着当前正在执行的那个方法

栈帧图解

多线程

栈帧是以线程为基本单位,每个线程都有自己的栈内存,有自己的多个栈帧

线程上下文切换

因为某些原因cpu不再执行当前的线程,转而执行其他线程。

  • 线程的CPU时间片用完。
  • 垃圾回收(暂停当前所有的线程)
  • 更高优先级的线程。
  • 线程自己调用了sleep ,yield ,wait , join, park,synchronized lock

当线程上下文切换时,要保证当前线程的状态。并恢复另一个线程的状态,JAVA中对应的概念就是程序计数器,作用是记录了下一条JVM指令的执行地址,是线程私有的。

  • 线程的状态包括程序计数器,虚拟机栈中每个栈帧的信息。
  • 线程的上下文切换频繁会影响性能

线程的常见方法

方法名

static

功能说明

注意

start()

启动一个新的线程

只能调用一次,多次会出现异常

run()

新的线程启动后会调用这个方法

如果实现了Runnable参数。则线程启动后会调用Runnable的run方法

join()

等待线程运行结束

join(long n)

等待线程运行结束,最多等n秒

getId()

获取线程长整型的id

id唯一

getName()

获取线程名

setName(String)

修改线程名

getPriority()

获取线程优先级

setPriority(int)

设置线程优先级

java中规定优先级1-10级,较大的优先级能提高调度几率

getState()

获取线程状态

Java中线程状态是用6个,分别是NEW...

isInterrupted()

判断是否被打断

不会清除标记(打断标记)

interrupt()

打断线程

如果打断线程正在sleep,waitjoin会导致被打断的线程抛出InterruptedException,并清除打断标记。如果打断正在运行的线程,则会设置打断标记。park的线程被打断也会被设置打断标记

interrupted()

static

判断当前线程是否被打断

会清除标记(打断标记)

currentThread()

static

isAlive()

线程是否存活

sleep(long n)

static

让当前执行的线程,休眠n毫秒,休眠时间让出CPU时间片

yield()

static

提示让出CPU

interrupted()

1.打断阻塞

打断sleep,wait,join的线程,会设置标记为false

打断正在运行时的线程,就会标记为true

public static void main(String[] args) throws InterruptedException {
    Thread thread=new Thread(new Runnable() {
        @Override
        public void run() {
            f1();
        }
    });
    Thread thread1=new Thread(new Runnable() {
        @Override
        public void run() {
            f2();
        }
    });
    thread.start();
    thread.interrupt();
    System.out.println("线程的状态"+thread.isInterrupted());
    thread.join();
}
public static void f1(){
    int a=1;
    System.out.println(a);

}

2.打断正常运行

public class StackTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){

                }

            }
        });

        thread.start();
        thread.interrupt();
        System.out.println("线程的状态"+thread.isInterrupted());
        thread.join();
    }
    public static void f1(){
        int a=1;
        System.out.println(a);

    }
 }

注意看,虽然打断成功了,但是线程并没有停止。这是因为这个打断只是告诉这个线程我要打断你了。具体停不停还得是看那个线程的自己的实现。

完整版

public class StackTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    Thread thread1=Thread.currentThread();

                    if(thread1.isInterrupted()){
                        System.out.println("线程被打断了");
                        break;
                    }

                }

            }
        });

        thread.start();
        thread.interrupt();
        System.out.println("线程的状态"+thread.isInterrupted());
        thread.join();
    }
    public static void f1(){
        int a=1;
        System.out.println(a);

    }

两阶段中止模式

在一个线程T1中如何优雅的中止线程T2?优雅就是给T2一个料理后事的机会

错误的思路

使用线程对象的stop()方法停止线程

stop()方法会真正的杀死线程。如果这时线程锁住了共享资源,那么被它杀死后就再也没有机会释放锁,其他线程将永远无法获取锁。

使用System.exit(int)方法停止线程。

目的:仅仅要停止一个线程,你这全停了。

具体实现

package algorithm;

import lombok.extern.slf4j.Slf4j;

public class Test3 {
    public static void main(String[] args) throws InterruptedException {
        TowPhaseTermination tpt=new TowPhaseTermination();
        tpt.start();
        Thread.sleep(10000);
        tpt.stop();
    }

}


class  TowPhaseTermination{
    private Thread monitor;

    public void start(){
        monitor=new Thread(()->{
            while (true){
                Thread current= Thread.currentThread();

                if(current.isInterrupted()){
                    System.out.println("料理后事...");
                    break;
                }
                try {
                    Thread.sleep(2000);
                    System.out.println(current.getName()+"执行监控记录");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //重新设置打断标记
                    current.interrupt();
                }
            }
        });
        
        monitor.start();
    }

    public void stop(){
        monitor.interrupt();;
    }

}

文章来源:https://blog.csdn.net/m0_62645012/article/details/135585098
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。