首页 > 编程语言 >[Java并发]Thread

[Java并发]Thread

时间:2024-06-23 17:01:01浏览次数:3  
标签:Runnable Java Thread 并发 线程 new run public

Java 开启线程的四种方式

实现runnable接口

这个方法有一个很大的缺点就是重写的run方法是没有返回值的,如果想要返回值,需要使用下面的方法

public class RunnableImpl implements Runnable {

    /*
    * 创建步骤如下:
    * 1,定义Runnable接口的实现类,并且实现run方法,这个方法同样是线程执行体
    * 2,创建Runnable实现类的实例,并以此实例对象作为Thread的target来创建Thread类,这个新创建的Thread对象才是真正的线程对象,即开启了新的线程
    * 3,调用线程对象的start()方法来开启该线程
    *
    * 调用示例:
    * //开启10个线程
    * for (int i = 0; i < 10; i++) {
    *     Thread thread = new Thread(new RunnableImpl());
    *     thread.start();
    * }
    * */

    /**
     * 实现Runnable接口的run方法,这个方法称为线程执行体
     * */
    @Override
    public void run() {
        doSomething();
    }

    /**
     * 需要处理的任务
     * */
    private void doSomething(){
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "执行" + i);
        }
    }
}

实现callable接口

实现callable接口的类的实例对象不能直接当做线程执行体传递给thread,

而是需要先用futuretask包裹,从实现callable转为实现runnable,

再把task传递给thread构造线程。

这种方法可以获得方法执行的返回值,并且可以自定义返回类型,返回值被task接收,

还可以抛出异常,

public class CallableImpl implements Callable<String> {

    /*
     * 创建步骤如下:
     * 1,定义实现Callable<V>接口的实现类,实现call方法,这个方法是线程执行体
     * 2,创建Callable<V>实现类的实例,借助FutureTask得到线程执行的返回值
     * 3,将FutureTask的实例,作为Thread的target来创建Thread类
     * 4,调用start方法,开启线程
     *
     * 调用示例:
     * Callable<String> tc = new CallableImpl();
     * FutureTask<String> task = new FutureTask<>(tc);
     * new Thread(task).start();
     * try {
     *     System.out.println(task.get());
     * } catch (InterruptedException | ExecutionException e) {
     *     e.printStackTrace();
     * }
     *
     * 说明:
     * 1.与使用Runnable相比, Callable功能更强大些
     * 2.实现的call()方法相比run()方法,可以返回值
     * 3.方法可以抛出异常
     * 4.支持泛型的返回值
     * 5.需要借助FutureTask类,比如获取返回结果
     * Future接口可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。
     * FutureTask是Futrue接口的唯一的实现类
     * FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值
     *
     * */

    private int ticket = 5;

    @Override
    public String call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println(doSomething());
        }

        return "出票任务完成";
    }

    public String doSomething() {
        String result = "";
        if (this.ticket > 0) {
            result = "出票成功,ticket=" + this.ticket--;
        } else {
            result = "出票失败,ticket=" + this.ticket;
        }
        return result;
    }
}

继承thread类

public class ExtendThread extends Thread {

    /*
    * 创建步骤如下:
    * 1,定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务。因此把run方法称为线程执行体。
    * 2,创建Thread子类的实例,即创建线程对象。本实例中是new一个ExtendThread,即可创建线程对象,也就是开启了一个线程
    * 3,调用线程对象的start()方法来启动该线程。
    *
    * 调用示例:
    * //循环10次即开启10个线程
    * for (int i = 0; i < 10; i++) {
    *     ExtendThread extendThread = new ExtendThread();
    *     extendThread.start();
    * }
    * */

    /**
     * 重写Thread类的run(),这个方法称为线程执行体
     * */
    @Override
    public void run() {
        doSomething();
    }

    /**
     * 需要处理的任务
     * */
    public void doSomething(){
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "执行" + i);
        }
    }
}

创建线程池

public class ThreadPool implements Runnable {

    /*
     * 创建步骤如下:
     * 1,定义Runnable接口的实现类,或者定义(继承Runnable接口的类)的实现类,并且实现run方法,这个方法是线程执行体
     * 2,创建一个自定义线程个数的线程池
     * 3,实例化Runnable接口的实现类
     * 4,将3步的实例,作为线程池实例的execute方法的command参数,开启线程
     * 5,关闭线程池
     *
     * 调用示例:
     * ExecutorService pool = Executors.newFixedThreadPool(2);
     * ThreadPool threadPool = new ThreadPool("AA");
     * ThreadPool threadPoo2 = new ThreadPool("BB");
     * pool.execute(threadPool);
     * pool.execute(threadPoo2);
     * pool.shutdown();
     *
     * 说明:
     * 示例中创建的是2个线程的线程池
     * execute方法是开启线程方法,实参要求是实现Runnable的类。所以,继承Thread类的子类也可以以线程池的方式开启线程,因为thread类实现了runnable接口
     *
     * */

    String name;
    public ThreadPool(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        doSomething();
    }

    /**
     * 需要处理的任务
     * */
    private void doSomething() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "执行" + i + ",name=" + this.name);
        }
    }
}

匿名内部类

public class Anonymous {

    /*
    * 创建步骤如下:
    * 匿名内部类本质上也是一个类实现了Runnable接口,重写了run方法,只不过这个类没有名字,直接作为参数传入Thread类
    *
    * 调用示例:
    * //开启10个线程
    * for (int i = 0; i < 10; i++) {
    *     Anonymous anonymous =new Anonymous();
    *     anonymous.myRun();
    * }
    *
    * */

    public void myRun(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                doSomething();
            }
        }).start();
    }

    /**
     * 需要处理的任务
     * */
    private void doSomething(){
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "执行" + i);
        }
    }
}

在Java中,A线程调用B线程做某些工作,对于B的结果,A线程只想等待特定的时间而非一直等待,应该怎么做?

在Java中,你可以使用Thread.join()方法来等待一个线程执行完成,但是这会一直等待直到被等待的线程执行完成为止。如果你希望在等待一段特定的时间后不再等待,你可以结合使用Thread.join()TimeUnit类。以下是一个示例:

public class Main {
    public static void main(String[] args) {
        // 创建B线程并启动
        Thread bThread = new Thread(() -> {
            // B线程执行一些工作
            // ...

            // 假设B线程执行完成后设置了一些结果
            System.out.println("B线程执行完成");
        });

        bThread.start();

        // A线程等待B线程执行一段时间
        try {
            long timeoutMillis = 5000; // 设置等待时间为5秒
            bThread.join(timeoutMillis);

            if (bThread.isAlive()) {
                // 如果B线程在超时时间内仍然没有执行完成
                System.out.println("B线程还未执行完成,超时退出");
            } else {
                // 如果B线程在超时时间内执行完成
                System.out.println("A线程继续执行,B线程执行完成");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,bThread.join(timeoutMillis)会等待B线程最多执行timeoutMillis毫秒的时间。如果B线程在超时时间内执行完成,那么A线程会继续执行,否则A线程会在超时后不再等待B线程而继续执行自己的逻辑。

标签:Runnable,Java,Thread,并发,线程,new,run,public
From: https://www.cnblogs.com/DCFV/p/18263619

相关文章

  • JAVA类与对象的基础概念(JAVA基础)
    类的定义1.定义:类可以看做是一个模版,或者图纸,系统根据类的定义来造出对象2.属性:用于定义该类或该类对象包含的数据或者说静态特征3.初始化∶定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化4.方法:用于定义该类或该类实例的行为特征和功能实现......
  • [Java并发]ConcurrentHashMap
    ConcurrentHashMapHashMap和ConcurrentHashMap的区别主要区别就是hashmap线程不安全,ConcurrentHashMap线程安全HashMap线程不安全,有以下两个问题put覆盖问题比如有两个线程A和B,首先A希望插入一个key-value对到HashMap中,首先计算记录所要落到的桶的索引坐标,然后获取到该桶......
  • [Java基础]String
    String常量池/运行时常量池java类编译之后生成的.class文件包含三部分信息,类的基本信息,常量池,方法的定义通过javap-vxxxx.class命令可以看到Constantpool:#1=Methodref#2.#3//java/lang/Object."<init>":()V#2=Class#4......
  • Java Stream 8 API
    动态多字段排序动态多字段排序假设我们有一个Person类,希望能够按照age和name进行动态排序。我们使用上述代码生成一个组合比较器来完成多字段排序。1.定义Person类java复制代码importjava.util.HashMap;importjava.util.Map;publicclassPerson{privateM......
  • [Golang并发]GMP模型
    什么是GoroutineGoroutine=Golang+Coroutine。Goroutine是golang实现的协程,是用户级线程。Goroutine的特点:相比线程,其启动的代价很小,以很小栈空间启动(2Kb左右)能够动态地伸缩栈的大小,最大可以支持到Gb级别工作在用户态,切换成很小与线程关系是n:m,即可以在n个系统线程上多......
  • vscode开发纯java项目兼容eclipse
    最近想使用vscode作为开发工具逐步替代eclipse,但是不影响eclipse作为项目管理的配置。以下是踩坑过程:1、项目之间的依赖。如主projectA依赖projectB,projectB并不是已jar包的形式,而是项目的形式在eclipse中的,eclipse有个很方便的功能是直接把项目添加进依赖中,vscode貌似找不到直接......
  • Java基础面试题下
    #Java基础面试题(下)>lecture:波哥#一、String相关面试题##1.为什么String在java中是不可变的?-如果不是不可变的:这种情况根本不可能,因为在字符串池的情况下,一个字符串对象/文字,例如“Test”已被许多参考变量引用,因此如果其中任何一个更改了值,其他参数将自动受到影......
  • 掌握Perl并发:线程与进程编程全攻略
    掌握Perl并发:线程与进程编程全攻略引言Perl作为一种功能强大的编程语言,提供了丰富的并发编程手段。无论是通过threads模块实现的线程,还是通过fork系统调用产生的进程,Perl都能帮助开发者高效地处理多任务。本文将深入探讨如何在Perl中使用线程和进程,带领读者掌握并发编程的......
  • 数据库系统概论(超详解!!!) 第十四节 数据库并发控制机制
    多用户数据库系统:允许多个用户同时使用的数据库系统例:飞机定票数据库系统银行数据库系统特点:在同一时刻并发运行的事务数可达数百上千个多事务执行方式:(1)事务串行执行每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行。不能充分利用系统资源,发挥数据库......
  • 1.4Java 基本数据类型
    变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。因此,通过定义不同类型的变量,可以在内存中储存整数、小数或者字符。Java的两大数据类型:内置数据类型引用......