高并发基础(二)

本文介绍了Java实现线程的四种方式,包括继承Thread、实现Runnable、Callable以及ExecutorService。重点讲解了线程中断、优先级及Join方法的使用。此外,还详细阐述了JVM内存模型的各个区域,如程序计数器、虚拟机栈、本地方法栈、堆和方法区,以及运行时常量池的概念。线程通信方面,讨论了共享内存和消息传递两种方式,如Volatile、wait()、notify()和Exchanger的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高并发基础(二)

实现方式:

​ 1,继承Thread类创建线程: Thread类本质上是实现了Runnable接口

​ 通过方法继承Thread既可,然后调用Start()

public class Threads extends Thread{
    @Override
    public void run() {
       System.out.println(Thread.currentThread().getName()+"实现run方法多线程");
    }
}

public static void main(String[] args) {
   for (int i = 0;i<10;i++){
      Threads t =  new Threads();
      t.setName("线程"+i);
      t.start();
   }
   System.out.println(Thread.currentThread().getName()+"主线程执行完成");
}
 执行启动方法后即可看到运行效果   

​ 2,实现Runnable接口: 如果自己的类已经继承了两一个类,就无法再继承Thread,因此可以实现一个Runnable接口

public class Runs implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

    public static void main(String[] args) {
        for (int i = 0;i<10;i++){
            Thread t =  new Thread(new Runs());
            t.setName("线程"+i);
            t.start();
        }
        System.out.println(Thread.currentThread().getName()+"主线程执行完成");
    }

​ 3,实现Callable接口通过FutureTask包装器创建线程

callable实现会有返回值
public class Callables implements Callable<String> {
    @Override
    public String call() throws Exception {
        return Thread.currentThread().getName();
    }
}
应用FutureTask 接收返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int i = 0;i<10;i++){
            FutureTask task = new FutureTask(new Callables());
            Thread t =  new Thread(task);
            t.setName("线程"+i);
            t.start();
            System.out.println("返回值:"+task.get());
        }
        System.out.println(Thread.currentThread().getName()+"主线程执行完成");
    }

​ 4,使用ExecutorService、Callable、Future实现有返回结果的线程

​ 此处ExecutorService不在这里演示了,后续线程池部分会有说明

​ 在正常开发中,也会涉及一些常见的情况,比如中断程序,优先执行、优先级等相关操作

​ Interrput:用来终止线程,原理:抛出异常中断异常,从而提前结束阻塞状态

public class Runs implements Runnable{
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){  //如果不是异常状态,则一直 执行
            System.out.println(Thread.currentThread().getName()+"执行中.........");
        }
        //更新异常状态后,调出循环
        System.out.println("执行完成");
    }
}

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Thread t =  new Thread(new Runs());
        t.setName("线程1");
        t.start();
        Thread.sleep(10);
        t.interrupt();  //此处将线程编程异常状态
        System.out.println(Thread.currentThread().getName()+"主线程执行完成");
    }
    因为main线程与thread线程是异步,所以等到main线程睡眠对应时间后,就在thread线程进行标记,Thread.currentThread().isInterrupted()变为true;标记之后,线程循环判断线程是否为非true,也就是false,如果是false,则跳出循环;这样就达到了线程的停止

​ SetPriority:设置线程优先级,默认为5, 但是不一定会优先执行,只是相对于会优先执行,

public class Runs implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行中.........");
    }
}
创建10个线程执行
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int i=0;i<10;i++){
            Thread t = new Thread(new Runs());
            t.setName("线程"+i);
            t.start();
            if (i==3){
                t.join();
            }
        }

        System.out.println("主线程执行完成");
    }
 主线程执行完成
线程2执行中.........
线程1执行中.........
线程3执行中.........
设置优先级后
t2.setPriority(9);
要看效果,最好每个线程都循环100次
优先级并不代表先执行,只是会优先执行完

​ Join:优先执行

​ 方式跟setPriority差不多

​ 跟优先级差不多,这种方式就会让设置join线程执行完成之后才会执行其他线程。后续使用较多

jvm内存模型

多线程开发必不可少的需要了解jvm内存模型

​ 程序计数器:当前线程所执行字节码的行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码指令

​ 虚拟机栈:描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java都会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每个方法被调用直至执行完毕的过程,就对应一个栈帧在虚拟机中从入栈到出栈的过程

本地方法栈:本地方法栈与虚拟机栈的作用基本上是一致的,区别在于虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务

​ 堆:Java堆(Heap)是虚拟机所管理的内存中最大的一块区域,Java堆是被所有线程共享的一块内存区域,唯一目的就是存放对象实例

​ 方法区:是线程共享的内存区域,存放已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据

​ 运行时常量池:是方法区的一部分,用于存放编译器内生成的各种字面量与符号引用,这部分内容将在内加载后存放到方法区的运行时常量池中

当一个线程修改了共享变量的值,其他线程会马上知道这个修改。当其他线程要读取这个变量的时候,最终会去内存中读取,而不是从缓存中读取

线程通信

线程通信


​ 共享内存:线程之间共享程序的公共状态(Vloatile),线程之间通过写-读内存中的公共状态来隐式进行通信

​ 消息传递:程之间没有公共状态,线程之间必须通过明确的发送消息来显式(ReentrantLock)进行通信,传递方式就是wait()和notify()

Exchanger:两个线成之间数据进行交换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平常心丷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值