Maison  >  Article  >  Java  >  Comment créer et exécuter des threads en Java ?

Comment créer et exécuter des threads en Java ?

王林
王林avant
2023-04-19 14:16:051585parcourir

    1. Cinq façons de créer et d'exécuter des threads

    La première : hériter de la classe Thread

    Cette méthode est la méthode la plus basique Les amis qui ont appris Java le savent et n'entreront pas dans les détails. Il convient de noter que : L'implémentation de la superposition utilise la méthode run et le thread en cours d'exécution utilise la méthode start.

    public class FirstWay extends Thread  {
        @Override
        public void run() {
            System.out.println("第一种实现线程的方式:继承Thread类");
        }
        //模拟测试
        public static void main(String[] args) {
            new FirstWay().start();
        }
    }

    Deuxième : implémenter l'interface Runnable

    La deuxième méthode d'implémentation est encore très basique. Elle hérite de l'interface Runnable et réécrit la méthode run pour implémenter la logique d'exécution des threads. Remarque : le thread en cours d'exécution nécessite une couche de nouveau thread. new Thread 。

    public class SecondWay implements Runnable{
        @Override
        public void run() {
            System.out.println("第二种实现线程的方式:实现Runnable接口");
        }
        //模拟测试
        public static void main(String[] args) {
            new Thread(new SecondWay()).start();
        }
    }

    第三种:实现Callable接口

    第三种方式是实现Callable接口,Callable接口与Runable接口都能实现线程。

    public class ThirdWay implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println("第三种实现线程的方式:实现Callable接口");
            return "Callable接口带返回值,可以抛出异常";
        }
    
        //模拟测试
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            FutureTask<String> futureTask = new FutureTask<>(new ThirdWay());
            new Thread(futureTask).start();
            //阻塞方法,获取call方法返回值
            System.out.println(futureTask.get());  //打印:Callable接口带返回值,可以抛出异常
        }
    }

    区别如下:

    • Callable接口实现线程方法是call, Runable接口实现线程方法是run

    • Callable有返回值, Runable接口不能有返回值

    • Callable接口方法call返回值可以设置泛型,如下例子中使用String数据类型

    • Callable接口方法call方法可以抛出异常,Runable接口run方法不可以抛出异常

    • Callable接口方法通过new Thread(futureTask).start()运行,FutureTask的get方法可以获取Callable接口方法call方法的返回值

    • 如果Callable接口方法call方法异常,在FutureTask的get方法调用时也会抛出同样的异常

    第四种:线程池 + execute

    从JDK5版本开始,java默认提供了线程池的支持,用线程池的方式运行线程可以避免线程的无限扩张导致应用宕机,同时也节省了线程频繁创建与销毁的资源与时间成本。

    public class FourthWay implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() +
                    ":实现线程的方式Runnable接口,但运行方式不一样,使用线程池");
        }
    
        public static void main(String[] args) {
            //创建一个固定大小的线程池
            ExecutorService threadPool = Executors.newFixedThreadPool(5);
            for(int i = 0;i < 10;i++){
                threadPool.execute(new FourthWay());
            }
        }
    }

    线程池ExecutorService使用execute方法运行Runnable接口run方法的线程实现,execute方法与run方法的共同特点是没有返回值。

    pool-1-thread-5:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-2:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-1:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-3:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-2:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
    pool-1-thread-5:实现线程的方式Runnable接口,但运行方式不一样,使用线程池

    从上面的结果中可以看出,线程池中包含五个线程。线程运行完成之后并不销毁,而是还回到线程池,下一次执行时从线程池中获取线程资源再次运行。

    第五种:线程池 + submit

    下面的例子线程池ExecutorService使用submit方法运行Callable接口call方法的线程实现,submit方法与call方法的共同特点是存在返回值。

    • Callable接口call方法的返回值可以由泛型定义

    • ExecutorService线程池submit方法的返回值是Future

    Future的get方法可以获取call方法的返回值,同时如果call方法抛出异常,Future的get方法也会抛出异常。

    public class FifthWay implements Callable<String> {
        @Override
        public String call() throws Exception {
            return Thread.currentThread().getName() + ":Callable接口带返回值,可以抛出异常";
        }
    
        //模拟测试
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //保存多线程执行结果
            List<String> retList = new ArrayList<>();
            //创建一个固定大小的线程池
            ExecutorService threadPool = Executors.newFixedThreadPool(5);
            for(int i = 0;i < 10;i++){
                Future<String> future = threadPool.submit(new FifthWay());
                retList.add(future.get());
            }
            //java8 语法,打印retlist
            retList.forEach(System.out::println);
        }
    }

    上文代码中有一个小小的语法糖,retList.forEach(System.out::println);

    pool-1-thread-1:Callable接口带返回值,可以抛出异常
    pool-1-thread-2:Callable接口带返回值,可以抛出异常
    pool-1-thread-3:Callable接口带返回值,可以抛出异常
    pool-1-thread-4:Callable接口带返回值,可以抛出异常
    pool-1-thread-5:Callable接口带返回值,可以抛出异常
    pool-1-thread-1:Callable接口带返回值,可以抛出异常
    pool-1-thread-2:Callable接口带返回值,可以抛出异常
    pool-1-thread-3:Callable接口带返回值,可以抛出异常
    pool-1-thread-4:Callable接口带返回值,可以抛出异常
    pool-1-thread-5:Callable接口带返回值,可以抛出异常

    La troisième façon : implémenter l'interface Callable🎜🎜La troisième méthode consiste à implémenter l'interface Callable et l'interface Runable peuvent implémenter des threads. 🎜rrreee🎜🎜La différence est la suivante : 🎜🎜
    • 🎜La méthode thread implémentée par l'interface Callable est call, et la méthode thread implémentée par l'interface Runable est exécutée 🎜
    • 🎜Callable Il existe une valeur de retour et l'interface Runable ne peut pas avoir de valeur de retour🎜
    • 🎜La valeur de retour de l'appel de la méthode de l'interface Callable peut être définie sur un type générique . Dans l'exemple suivant, le type de données String est utilisé🎜
    • 🎜Les méthodes d'appel de méthode d'interface callable peuvent lever des exceptions, mais la méthode run de l'interface Runable ne peut pas lever d'exceptions🎜
    • 🎜. Les méthodes d'interface appelables sont exécutées via new Thread(futureTask).start() et la méthode get de FutureTask. Vous pouvez obtenir la valeur de retour de la méthode d'appel de la méthode d'interface appelable🎜
    • 🎜Si la méthode d'appel de la méthode d'interface Callable est anormale, la même exception sera levée lorsque la méthode get de FutureTask est appelée🎜
    • 🎜🎜Quatrième type : pool de threads + exécution🎜🎜À partir de la version JDK5, Java fournit la prise en charge du pool de threads par défaut. L'exécution de threads dans un pool de threads peut éviter les temps d'arrêt des applications causés par l'expansion infinie des threads, et permet également d'économiser le temps de création et de destruction fréquente de threads. 🎜rrreee🎜🎜Le pool de threads ExecutorService utilise la méthode d'exécution pour exécuter l'implémentation de thread de la méthode run de l'interface Runnable. La caractéristique commune de la méthode d'exécution et de la méthode d'exécution est qu'il n'y a pas de valeur de retour. 🎜🎜rrreee🎜Comme vous pouvez le voir d'après les résultats ci-dessus, le pool de threads contient cinq threads. Une fois le thread terminé, il n'est pas détruit, mais renvoyé au pool de threads. Les ressources du thread sont obtenues à partir du pool de threads et réexécutées lors de la prochaine exécution. 🎜🎜Cinquième méthode : Pool de threads + submit🎜🎜🎜L'exemple de pool de threads suivant ExecutorService utilise la méthode submit pour exécuter l'implémentation de thread de la méthode d'appel de l'interface Callable. La caractéristique commune de la méthode submit et de la méthode call est l'existence. d'une valeur de retour. 🎜🎜
      • 🎜La valeur de retour de la méthode d'appel de l'interface Callable peut être définie par des génériques🎜
      • 🎜La valeur de retour de la méthode de soumission du pool de threads ExecutorService est Future🎜
      • 🎜🎜La méthode get de Future peut obtenir la valeur de retour de la méthode d'appel en même temps, si la méthode d'appel lève une exception, la méthode get de Future lèvera également. une exception. 🎜🎜rrreee🎜Il y a un petit sucre syntaxique dans le code ci-dessus, retList.forEach(System.out::println); est une référence de méthode fournie par java8🎜rrreee

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer