首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面试系列之-线程创建方法(JAVA基础)

面试系列之-线程创建方法(JAVA基础)

作者头像
用户4283147
发布于 2023-08-21 12:19:09
发布于 2023-08-21 12:19:09
15500
代码可运行
举报
文章被收录于专栏:对线JAVA面试对线JAVA面试
运行总次数:0
代码可运行
  1. 继承Thread类创建线程类

(1)需要继承Thread类,创建一个新的线程类;

(2)同时重写run()方法,将需要并发执行的业务代码编写在run()方法中;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CreateDemo {
    public static final int MAX_TURN = 5;
    public static String getCurThreadName() {
        return Thread.currentThread().getName();
    }
    //线程的编号
    static int threadNo = 1;
    static class DemoThread extends Thread { //①
        public DemoThread() {
            super("DemoThread-" + threadNo++); //②
        }
        public void run() { //③
            for (int i = 1; i < MAX_TURN; i++) {
                Print.cfo(getName() + ", 轮次:" + i);
            }
            Print.cfo(getName() + " 运行结束.");
        }
    }
    public static void main(String args[]) throws InterruptedException {
        Thread thread = null;
        //方法一:使用Thread子类创建和启动线程
        for (int i = 0; i < 2; i++) {
            thread = new DemoThread();
            thread.start();
        }
        Print.cfo(getCurThreadName() + " 运行结束.");
    }
}
  1. 实现Runnable接口创建线程目标类

2.1 通过匿名类创建Runnable线程目标类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CreateDemo2 {
    public static final int MAX_TURN = 5;
    static int threadNo = 1;
    public static void main(String args[]) throws InterruptedException {
        Thread thread = null;
        //使用Runnable的匿名类创建和启动线程
        for (int i = 0; i < 2; i++) {
            thread = new Thread(new Runnable() { //① 匿名实例
                @Override
                public void run() { //② 异步执行的业务逻辑
                    for (int j = 1; j < MAX_TURN; j++) {
                        Print.cfo(getCurThreadName() + ", 轮次:" + j);
                    }
                    Print.cfo(getCurThreadName() + " 运行结束.");
                }
            }, "RunnableThread" + threadNo++);
            thread.start();
        }
        Print.cfo(getCurThreadName() + " 运行结束.");
    }
}

2.2 实现Runnable接口的方式创建线程目标类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.crazymakercircle.multithread.basic.create;
// 省略import
public class SalesDemo{
    public static final int MAX_AMOUNT = 5; //商品数量
    //商店商品类(销售线程类),一个商品一个销售线程,每个线程异步销售4次
    static class StoreGoods extends Thread{
        StoreGoods(String name){
            super(name);
        }
        private int goodsAmount = MAX_AMOUNT;
        public void run(){
            for (int i = 0; i <= MAX_AMOUNT; i++){
                if (this.goodsAmount > 0){
                    Print.cfo(getCurThreadName() + " 卖出一件,还剩:"
                              + (--goodsAmount));
                    sleepMilliSeconds(10);
                }
            }
            Print.cfo(getCurThreadName() + " 运行结束.");
        }
    }
    //商场商品类(target销售线程的目标类),一个商品最多销售4次,可以多人销售
    static class MallGoods implements Runnable{
        //多人销售可能导致数据出错,使用原子数据类型保障数据安全
        private AtomicInteger goodsAmount = new AtomicInteger(MAX_AMOUNT);
        public void run(){
            for (int i = 0; i <= MAX_AMOUNT; i++){
                if (this.goodsAmount.get() > 0){
                    Print.cfo(getCurThreadName() + " 卖出一件,还剩:"
                              + (goodsAmount.decrementAndGet()));
                    sleepMilliSeconds(10);
                }
            }
            Print.cfo(getCurThreadName() + " 运行结束.");
        }
    }
    public static void main(String args[]) throws InterruptedException{
        Print.hint("商店版本的销售");
        for (int i = 1; i <= 2; i++){
            Thread thread = null;
            thread = new StoreGoods("店员-" + i);
            thread.start();
        }
        Thread.sleep(1000);
        Print.hint("商场版本的销售");
        MallGoods mallGoods = new MallGoods();
        for (int i = 1; i <= 2; i++){
            Thread thread = null;
            thread = new Thread(mallGoods, "商场销售员-" + i);
            thread.start();
        }
        Print.cfo(getCurThreadName() + " 运行结束.");
    }
}
  1. 使用Callable和FutureTask创建线程

对Future接口的主要方法详细说明如下:

·V get():获取异步任务执行的结果。注意,这个方法的调用是阻塞性的。如果异步任务没有执行完成,异步结果获取线程(调用线程)会一直被阻塞,一直阻塞到异步任务执行完成,其异步结果返回给调用线程。

·V get(Long timeout,TimeUnit unit):设置时限,(调用线程)阻塞性地获取异步任务执行的结果。该方法的调用也是阻塞性的,但是结果获取线程(调用线程)会有一个阻塞时长限制,不会无限制地阻塞和等待,如果其阻塞时间超过设定的timeout时间,该方法将抛出异常,调用线程可捕获此异常。

·boolean isDone():获取异步任务的执行状态。如果任务执行结束,就返回true。

·boolean isCancelled():获取异步任务的取消状态。如果任务完成前被取消,就返回true。

·boolean cancel(boolean mayInterruptRunning):取消异步任务的执行。

FutureTask类和Callable接口的联合使用可以创建能够获取异步执行结果的线程:

(1)创建一个Callable接口的实现类,并实现其call()方法,编写好异步执行的具体逻辑,可以有返回值。

(2)使用Callable实现类的实例构造一个FutureTask实例。

(3)使用FutureTask实例作为Thread构造器的target入参,构造新的Thread线程实例。

(4)调用Thread实例的start()方法启动新线程,启动新线程的run()方法并发执行。其内部的执行过程为:启动Thread实例的run()方法并发执行后,会执行FutureTask实例的run()方法,最终会并发执行Callable实现类的call()方法。

(5)调用FutureTask对象的get()方法阻塞性地获得并发线程的执行结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CreateDemo3 {
    public static final int MAX_TURN = 5;
    public static final int COMPUTE_TIMES = 100000000;
    //①创建一个 Callable 接口的实现类
    static class ReturnableTask implements Callable<Long> {
        //②编写好异步执行的具体逻辑,可以有返回值
        public Long call() throws Exception{
            long startTime = System.currentTimeMillis();
            Print.cfo(getCurThreadName() + " 线程运行开始.");
            Thread.sleep(1000);
            for (int i = 0; i < COMPUTE_TIMES; i++) {
                int j = i * 10000;
            }
            long used = System.currentTimeMillis() - startTime;
            Print.cfo(getCurThreadName() + " 线程运行结束.");
            return used;
        }
    }
    public static void main(String args[]) throws InterruptedException {
        ReturnableTask task=new ReturnableTask();//③
        FutureTask<Long> futureTask = new FutureTask<Long>(task);//④
        Thread thread = new Thread(futureTask, "returnableThread");//⑤
        thread.start();//⑥
        Thread.sleep(500);
        Print.cfo(getCurThreadName() + " 让子弹飞一会儿.");
        Print.cfo(getCurThreadName() + " 做一点自己的事情.");
        for (int i = 0; i < COMPUTE_TIMES / 2; i++) {
            int j = i * 10000;
        }
        Print.cfo(getCurThreadName() + " 获取并发任务的执行结果.");
        try {
            Print.cfo(thread.getName()+"线程占用时间:"
                      + futureTask.get());//⑦
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Print.cfo(getCurThreadName() + " 运行结束.");
    }
}
  1. 通过线程池创建线程
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CreateDemo4{
    public static final int MAX_TURN = 5;
    public static final int COMPUTE_TIMES = 100000000;
    //创建一个包含三个线程的线程池
    private static ExecutorService pool = Executors.newFixedThreadPool(3);
    static class DemoThread implements Runnable{
        @Override
        public void run(){
            for (int j = 1; j < MAX_TURN; j++){
                Print.cfo(getCurThreadName() + ", 轮次:" + j);
                sleepMilliSeconds(10);
            }
        }
    }
    static class ReturnableTask implements Callable<Long>{
        //返回并发执行的时间
        public Long call() throws Exception{
            long startTime = System.currentTimeMillis();
            Print.cfo(getCurThreadName() + " 线程运行开始.");
            for (int j = 1; j < MAX_TURN; j++){
                Print.cfo(getCurThreadName() + ", 轮次:" + j);
                sleepMilliSeconds(10);
            }
            long used = System.currentTimeMillis() - startTime;
            Print.cfo(getCurThreadName() + " 线程运行结束.");
            return used;
        }
    }
    public static void main(String[] args) {
        pool.execute(new DemoThread()); //执行线程实例,无返回
        pool.execute(new Runnable(){
          @Override
          public void run(){
            for (int j = 1; j < MAX_TURN; j++){
              Print.cfo(getCurThreadName() + ", 轮次:" + j);
              sleepMilliSeconds(10);
            }
          }
      });
        //提交Callable 执行目标实例,有返回
        Future future = pool.submit(new ReturnableTask());
        Long result = (Long) future.get();
        Print.cfo("异步任务的执行结果为:" + result);
        sleepSeconds(Integer.MAX_VALUE);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 对线JAVA面试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
JVM:全面解析Java对象的创建、内存布局 & 访问定位流程
由于引用类型数据(reference)在 Java虚拟机中只规定了一个指向对象的引用,但没定义该引用应该通过何种方式去定位、访问堆中的对象的具体位置
Carson.Ho
2019/10/25
1.9K0
jvm学习记录-对象的创建、对象的内存布局、对象的访问定位
简述 今天继续写《深入理解java虚拟机》的对象创建的理解。这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录。 (此文中所阐述的内容都是以HotSpot虚拟机为例的。) 对象的创建 java程序在运行过程中无时无刻都有对象被创建出来,那么创建对象是个怎么样的过程呢?还是看看我自己的理解吧。 判断是否已经执行类加载 当虚拟机遇到一条new指令时 ,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化
纪莫
2018/04/19
1.1K0
jvm学习记录-对象的创建、对象的内存布局、对象的访问定位
浅谈对象的创建、内存布局和访问定位
  这里的对象的创建是指普通的对象(不包括数组和Class对象)。对象的创建简单来说就是执行new的时候,虚拟机做出对应的响应。让我们看看一下虚拟机创建对象的过程: 1.虚拟机遇到new指令时,首先尝试在常量池中定位到对应类的符号引用,并检查这个符号引用代表类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程(后续会写一下关于类加载的问题)。 2.类加载检查通过后,为新生对象分配内存。对象内存的大小在类加载完成后便可完全确定。对象内存分配有“指针碰撞”和“空闲列表”两种方法,“指针碰撞”是把已用内存放到指针的一边,未用的放到另一边,以指针分隔,当需要分配一个新对象内存时把指针往未分配内存那边移动相对应的空间即可;“空闲列表”是因为内存已用的和未用的并不是规整的,它们是交错的,所以需要一个列表记录内存块的情况。Java堆是线程之间共享的内存,虚拟机采用CAS配上失败重试的方式保证更新操作的原子性保证内存指针修改并发安全性;另一种方法是“本地线程分配缓冲(Thread Local Allocation Buffer TLAB)”。 3.将虚拟机分配到的内存空间初始化为零值。 4.对对象进行必要的设置。其实是对对象头编写。 5.完成上面4个步骤执行new指令后会接着执行方法 到此对象才算完成生产出来。
GreizLiao
2019/09/24
8050
JVM之对象的实例化内存布局与访问定位
将对象的所属类(即类的元数据信息)、对象的HashCode和对象的GC信息、锁信息等数据存储在对象的对象头中。这个过程的具体设置方式取决于JVM实现
Java微观世界
2025/01/20
1340
JVM之对象的实例化内存布局与访问定位
JVM之对象创建流程及对象内存布局
当JAVA虚拟机碰到new字节码指令时,首先会去常量池中查找是否有对应的类名(也就是去查找是否有对应的符号引用),然后去检查这个符号引用代表的类是否已经被加载,解析和初始化过。如果没有会先进行类加载过程。
北洋
2021/12/20
5180
一文详解JVM对象内存布局以及内存分配规则
对象头可能包含类型指针,通过该指针能确定对象属于哪个类。如果对象是一个数组,那么对象头还会包括数组长度。
架构狂人
2023/08/16
5020
一文详解JVM对象内存布局以及内存分配规则
JVM02-JVM的对象创建以及访问方式
前言对象创建1.类加载检查2.分配内存分配内存的方式内存分配的并发问题3.初始化零值4.设置对象头:5. 执行init方法;对象内存布局对象头实例数据对齐填充对象访问方式使用句柄访问使用直接指针访问总结
码农飞哥
2021/08/18
5270
JVM-解密Java对象
在Java程序运行过程中时时刻刻都有对象被创建出来,对象的创建方式有很多种,最常见的就是new,其次还有clone和反序列化。下面我们一起来解密对象的创建、内存布局以及如何定位一个对象。
shysh95
2020/08/11
4080
深入理解JVM - 对象分配内存
这一节我们来讨论对象分配内存的细节,这一块的内容相对比较简单,但是也是比较重要的内容,最后会总结书里面的OOM的溢出案例,在过去的文章已经讲到过不少类似的情况。
阿东
2021/08/16
4490
JVM-02内存区域与内存溢出异常(中)【hotspot虚拟机对象】
在 JVM-01自动内存管理机制之Java内存区域与内存溢出异常(上)中我们介绍了 运行时数据区域,这里我们来继续探讨下hotspot虚拟机对象
小小工匠
2021/08/17
3780
最通俗易懂的JVM内存管理与对象创建原理
对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要像 C/C++程序为每一个new操作去写配对 的delete/free代码,不容易出现内存泄漏和内存溢出问题。也正是因为Java程序员把控制内存的权力交给了Java虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那排查错误、修正问题将会成为一项异常艰难的工作。
仲君Johnny
2024/01/24
5150
最通俗易懂的JVM内存管理与对象创建原理
JVM内存与垃圾回收篇第10章对象的实例化内存布局与访问定位
将对象的所属类(即类的元数据信息)、对象的HashCode和对象的GC信息、锁信息等数据存储在对象的对象头中。这个过程的具体设置方式取决于JVM实现。
yuanshuai
2022/08/17
2760
JVM内存与垃圾回收篇第10章对象的实例化内存布局与访问定位
JVM 中对象咋创建啊,又怎么访问啊
多学一点,这里的几个步骤涉及多个指令操作,所以就有了 DCL 单例使用 volatile 来禁止指令重排来保证单例模式的实例同步
星尘的一个朋友
2020/12/30
6660
JVM 中对象咋创建啊,又怎么访问啊
《深入理解Java虚拟机》读书笔记(二)
当Java虚拟机遇到字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过;如果没有,那么必须先执行相应的类加载过程
DestinySkywalker
2023/01/01
3760
《深入理解Java虚拟机》读书笔记(二)
深入理解JVM(③)——之HotSpot虚拟机对象探秘
上篇文章介绍了Java虚拟机的运行时数据区域,大致明白了Java虚拟机内存模型的概况,下面就基于实用优先的原则,以最常用的虚拟机HotSpot和最常用的内存区域Java堆为例,升入探讨一下HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程。
纪莫
2020/06/04
6520
JVM 系列(2) —— Java 的对象
当 Java 虚拟机遇到一条字节码指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号的引用,并检查这个符号引用代表的类是否被加载解析和初始化过。如果没有则先执行相应的类加载过程。
求和小熊猫
2020/12/18
4190
JVM 系列(2) —— Java 的对象
HotSpot 虚拟机对象
虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数,是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化。如果没有,那必须先执行相应的类加载过程。
happyJared
2019/07/27
5290
JVM系列一(Java内存区域和对象创建).
线程共享,JVM中最大的一块内存,此内存的唯一目的就是存放对象实例,Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”(Garbage Collected Heap),可以通过 -Xmx 和 -Xms 参数来控制该区域大小。
JMCui
2019/12/02
4870
JVM系列一(Java内存区域和对象创建).
深入浅出JVM(一)之Hotspot虚拟机中的对象
对象的创建可以分为五个步骤:检查类加载,分配内存,初始化零值,设置对象头,执行实例构造器<init>
菜菜的后端私房菜
2024/09/24
3160
JVM:HotSpot虚拟机----对象的创建简单介绍及对象内存布局详解
例如:在32位HotSpot虚拟机中,如果对象处于未被锁定的状态下,那么Mark Word的32bit空间中的25bit用于存储对象哈希码,4bit用于存储对象分代年龄,2bit用于存储锁标志位,1bit固定为0。下表是不同状态下对象存储内容的详细表:
鲲志说
2025/04/07
1560
JVM:HotSpot虚拟机----对象的创建简单介绍及对象内存布局详解
推荐阅读
相关推荐
JVM:全面解析Java对象的创建、内存布局 & 访问定位流程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档