Quatre façons de créer un thread de thread, exécutable, appelable et ExecutorService

Quatre façons de créer des threads

1. Héritez de la classe Thread
2. Implémentez la classe Runnable
3. Implémentez la classe Callable
4. Créez un thread via le pool de threads: une file d'attente de threads est fournie dans laquelle tous les threads en attente sont stockés. Évitez la création et la destruction de frais généraux supplémentaires, améliorez la vitesse de réponse

Architecture:
java.util.concurrent.Executor: l'interface racine responsable de l'utilisation et de la planification des threads
| –Sous-interfaceExecutorService: l'interface principale du
pool de threads | –ThreadPoolExecutor classe d'implémentation du pool de threads
| –ScheduledExecutorService sous-interface: responsable de la planification des threads
| -ScheduledThreadPoolExecutor: hérite de ThreadPoolExecutor, implémente ScheduledExecutorService *

Outils: Executors
ExecutorService newFixedThreadPool (): Créer un pool de threads de taille fixe
ExecutorService newCachedThreadPool (): Cache thread pool. Le nombre de threads n'est pas fixe et le nombre peut être changé automatiquement en fonction de la demande.
ExecutorService newSingleThreadExecutor (): crée un pool de threads unique. Il n'y a qu'un seul thread dans le pool de threads
ScheduledExecutorService newScheduledThreadPool (): crée un thread de taille fixe qui peut exécuter des tâches de manière différée ou programmée.

détails comme suit:

Premièrement, héritez de la classe Thread

Les étapes pour créer un thread en héritant de la classe Thread sont les suivantes:
(1) créer une classe pour hériter de la classe Thread, réécrire la méthode run () et écrire le code de la tâche à effectuer dans la méthode run ();
( 2) Créez une sous-classe de la classe Thread Object;
(3) Appelez la méthode start () de l'objet, la méthode start () signifie démarrer le thread en premier, puis appelez la méthode run ();

public class ThreadTest {
    public static void main(String[] args) {
        window t1 = new window();
        window1 t2 = new window1();
        t1.setName("售票口1");
        t2.setName("售票口2");
        t1.start();
        t2.start();
        if(t1.isInterrupted() == true){
            t1.interrupt();
            System.out.println("线程1停止");
        }
    }
    static class window extends Thread{
       //将其加载在类的静态区,所有线程共享该静态变量
        private static int ticket = 10; 
        @Override
        public synchronized void run() {
            while(true){
                if(ticket>0){
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName()+"当前售出第"+ticket+"张票");
                    ticket--;
                }else{
                    interrupt();
                    System.out.println("1正在判断线程是否终止"+isInterrupted());
                    break;
                }
                System.out.println("1正在判断线程是否终止@@"+isInterrupted());
            }
        }
    }

   static class window1 extends Thread{
     //将其加载在类的静态区,所有线程共享该静态变量
        private static int ticket = 5; 
        @Override
        public synchronized void run() {
            while(true){
                if(ticket>0){
                    System.out.println(getName()+"当前售出第"+ticket+"张票");
                    try {
                        sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                }else{
                    interrupt();
                    System.out.println("2正在判断线程是否终止"+isInterrupted());
                    break;
                }
                System.out.println("2正在判断线程是否终止"+isInterrupted());
            }
        }
    }
 }

Modificateur de thread, type de retour, méthode et description:

修饰符、返回类型、方法和说明
static int	activeCount()
返回当前线程的线程组及其子组中活动线程的数量的估计值。
void	checkAccess()
确定当前正在运行的线程是否有权修改此线程。
protected Object	clone()
抛出CloneNotSupportedException,因为无法有意义地克隆线程。
int	countStackFrames()
不推荐使用。 
此调用的定义取决于suspend()已弃用的。此外,此调用的结果从未明确定义。
static Thread	currentThread()
返回对当前正在执行的线程对象的引用。
void	destroy()
不推荐使用。 
此方法最初设计为在不进行任何清理的情况下破坏此线程。它所持有的任何监视器都将保持锁定状态。但是,该方法从未实现。如果要实施,那么它在很大程度上将很容易死锁suspend()。如果目标线程在销毁关键系统资源时持有锁来保护它,则任何线程都无法再次访问该资源。如果另一个线程曾试图锁定此资源,则将导致死锁。这种僵局通常表现为“冻结”进程。有关更多信息,请参见 为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?。
static void	dumpStack()
将当前线程的堆栈跟踪记录打印到标准错误流。
static int	enumerate(Thread[] tarray)
将当前线程的线程组及其子组中的每个活动线程复制到指定的数组中。
static Map<Thread,StackTraceElement[]>	getAllStackTraces()
返回所有活动线程的堆栈跟踪的映射。
ClassLoader	getContextClassLoader()
返回此线程的上下文ClassLoader。
static Thread.UncaughtExceptionHandler	getDefaultUncaughtExceptionHandler()
返回由于未捕获的异常导致线程突然终止时调用的默认处理程序。
long	getId()
返回此线程的标识符。
String	getName()
返回此线程的名称。
int	getPriority()
返回此线程的优先级。
StackTraceElement[]	getStackTrace()
返回表示该线程的堆栈转储的堆栈跟踪元素的数组。
Thread.State	getState()
返回此线程的状态。
ThreadGroup	getThreadGroup()
返回该线程所属的线程组。
Thread.UncaughtExceptionHandler	getUncaughtExceptionHandler()
返回此线程由于未捕获的异常而突然终止时调用的处理程序。
static boolean	holdsLock(Object obj)
当且仅当当前线程在指定对象上持有监视器锁时,才返回true。
void	interrupt()
中断此线程。
static boolean	interrupted()
测试当前线程是否已被中断。
boolean	isAlive()
测试此线程是否仍然存在。
boolean	isDaemon()
测试此线程是否是守护程序线程。
boolean	isInterrupted()
测试此线程是否已被中断。
void	join()
等待该线程死亡。
void	join(long millis)
等待最多millis毫秒,直到该线程消失。
void	join(long millis, int nanos)
等待最多millis毫秒加 nanos十亿分之一秒的时间,以使该线程死亡。
void	resume()
不推荐使用。 
该方法仅适用于与suspend(),因为它容易死锁,因此已弃用。有关更多信息,请参见 为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?。
void	run()
如果此线程是使用单独的 Runnable运行对象构造的,则调用该Runnable对象的run方法;否则,将调用该 对象的方法。否则,此方法不执行任何操作并返回。
void	setContextClassLoader(ClassLoader cl)
设置此线程的上下文ClassLoader。
void	setDaemon(boolean on)
将此线程标记为守护程序线程或用户线程。
static void	setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
设置当线程由于未捕获的异常而突然终止并且没有为该线程定义其他处理程序时调用的默认处理程序。
void	setName(String name)
将此线程的名称更改为等于参数 name。
void	setPriority(int newPriority)
更改此线程的优先级。
void	setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
设置当此线程由于未捕获的异常突然终止时调用的处理程序。
static void	sleep(long millis)
根据系统计时器和调度程序的精度和准确性,使当前正在执行的线程进入休眠状态(暂时停止执行)达指定的毫秒数。
static void	sleep(long millis, int nanos)
根据系统计时器和调度程序的精度和准确性,使当前正在执行的线程进入休眠状态(暂时停止执行)达指定的毫秒数加上指定的纳秒数。
void	start()
使该线程开始执行;Java虚拟机将调用run此线程的方法。
void	stop()
不推荐使用。 
这种方法本质上是不安全的。使用Thread.stop停止线程会导致它解锁所有已锁定的监视器(由于未经检查的ThreadDeath异常会自然 传播堆栈)。如果先前由这些监视器保护的任何对象处于不一致状态,则损坏的对象将变为其他线程可见,从而可能导致任意行为。的许多用途stop应该用简单地修改一些变量以指示目标线程应该停止运行的代码代替。目标线程应定期检查此变量,如果该变量指示它将停止运行,则应有序地从其运行方法返回。如果目标线程等待很长时间(例如,在条件变量上),interrupt则应使用该方法来中断等待。有关更多信息,请参见 为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?。
void	stop(Throwable obj)
不推荐使用。 
这种方法本质上是不安全的。有关stop() 详细信息,请参见。此方法的另一个危险是,它可能会用于生成目标线程不准备处理的异常(包括如果该方法不支持该线程,则可能无法抛出的已检查异常)。有关更多信息,请参见 为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?。
void	suspend()
不推荐使用。 
此方法已被弃用,因为它固有地容易死锁。如果目标线程在挂起时在监视器上持有锁以保护关键系统资源,则在恢复目标线程之前,没有线程可以访问该资源。如果将恢复目标线程的线程在调用之前尝试锁定此监视器resume,则会导致死锁。这种僵局通常表现为“冻结”进程。有关更多信息,请参见 为什么不赞成使用Thread.stop,Thread.suspend和Thread.resume?。
String	toString()
返回此线程的字符串表示形式,包括线程的名称,优先级和线程组。
static void	yield()
向调度程序提示当前线程愿意放弃当前使用的处理器。

Deuxièmement, implémentez la classe Runnable

Les étapes pour implémenter la classe Runnable pour créer un thread sont:
(1) Créez une classe pour implémenter la classe Runnable, réécrivez la méthode run () et écrivez le code de la tâche à compléter dans la méthode run ();
( 2) Créez une sous-classe de la classe Runnable Object;
(3) Vous devez d'abord instancier un Thread et passer votre propre instance MyRunnable.
(4) Appelez la méthode start () de l'objet. La méthode start () signifie démarrer le thread d'abord, puis appelez la méthode run ();

public class TestRunnable {
    public static void main(String[] args) {
		MyRunnable myRunnable = new MyRunnable ();
		new Thread(myRunnable).start();
	}
}
 
class MyRunnable implements Runnable{
	@Override
	public void run() {
		boolean flag = false;
		for(int i  = 3 ; i < 100 ; i ++) {
			flag = false;
			for(int j = 2; j <= Math.sqrt(i) ; j++) {
				if(i % j == 0) {
					flag = true;
					break;
				}
			}
			if(flag == false) {
				System.out.print(i+"  ");
			}
		}
	}

résultat de l'opération:

3  5  7  11  13  17  19  23  29  31  37  41  43  47  53  59  61  67  71  73  79  83  89  97

Toutes les sous-interfaces connues:
RunnableFuture, RunnableScheduledFuture
V-le type de résultat renvoyé par la méthode get de ce Future

Vous pouvez également démarrer le thread directement par d executor.execute (new RunnableTask1 ()) de ExecutorService

Troisièmement, implémentez la classe Callable

Les étapes pour implémenter la classe Callable pour créer un thread sont:
(1) Créez une classe pour implémenter la classe Callable, réécrivez la méthode run () et écrivez le code de la tâche à compléter dans la méthode run (), qui peut avoir un thread avec une valeur de retour;
(2) Créer un objet d'une sous-classe de la classe Callable;
(3) Vous devez d'abord instancier une FutureTask et passer votre propre instance myCallable
(4) Vous devez d'abord instancier un Thread et passez votre propre instance FutureTask
(5) Appelez la méthode object start (), la méthode start () signifie démarrer le thread en premier, puis appelez la méthode run ();

Avantages : Vous pouvez appeler la méthode
get () de FutureTask pour obtenir la valeur de retour. Comme cette méthode est bloquante, vous devez attendre que le thread se termine, parfois cela prend beaucoup de temps. Il est donc parfois nécessaire de définir le délai d'expiration.
get (long var1, TimeUnit var3) Le premier paramètre de cette méthode est un nombre entier long, et le second paramètre est l'unité
cancel (boolean mayInterruptIfRunning). Annuler la tâche,
passer true, la tâche en cours sera annulée, en cas de succès, return true, fail Renvoyer false;
transmettre false pour n'annuler que les tâches non démarrées et les tâches en cours d'exécution s'exécuteront avec succès.
La méthode isCancelled indique si la tâche est annulée avec succès, si elle est annulée avec succès avant que la tâche ne se termine normalement, elle renvoie true.
La méthode isDone indique si la tâche est terminée, si la tâche est terminée, elle renvoie true;

public class TestCallable {
    public static void main(String[] args) {

        MyCallable myCallable = new MyCallable();
        //FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。
        FutureTask futureTask = new FutureTask(myCallable);
        Thread thread =new Thread(futureTask);
        thread.start();
    }

    static class MyCallable implements Callable{

        List<Object> list = new ArrayList<>();
        @Override
        public Object call() throws Exception {
            boolean flag = false;
            for(int i  = 3 ; i < 100 ; i ++) {
                flag = false;
                for(int j = 2; j <= Math.sqrt(i) ; j++) {
                    if(i % j == 0) {
                        flag = true;
                        break;
                    }
                }
                if(flag == false) {
                    System.out.print(i+"  ");
                   list.add(i);
                }
            }
            return list;
        }
    }
}

résultat de l'opération:

3  5  7  11  13  17  19  23  29  31  37  41  43  47  53  59  61  67  71  73  79  83  89  97

Quatrièmement, la façon de créer un pool de threads

Les étapes de création du pool de threads sont les suivantes:
(1) créer d'abord un ExecutorService du pool de threads,
(2) Instancier un objet Callable et réécrire la méthode call (), qui peut avoir une valeur de retour;
(3) Appeler executorService.submit (appelable)) Cette méthode retourne un objet Future, qui peut être utilisé pour recevoir les résultats d'une exécution multithread.
Ou la méthode executorService.execute (myRunnale) renvoie un objet Future, qui peut être utilisé pour recevoir les résultats de l'exécution de plusieurs threads.

Avantage : vous pouvez appeler la méthode
get () de Future pour obtenir la valeur de retour, puis parce que cette méthode est bloquante, elle a attendu que le thread se termine, parfois cela prend beaucoup de temps. Il est donc parfois nécessaire de définir le délai d'expiration.
get (long var1, TimeUnit var3) Le premier paramètre de cette méthode est un nombre entier long, et le second paramètre est l'unité
cancel (boolean mayInterruptIfRunning). Annuler la tâche,
passer true, la tâche en cours sera annulée, en cas de succès, return true, fail Renvoyer false;
transmettre false pour n'annuler que les tâches non démarrées et les tâches en cours d'exécution s'exécuteront avec succès.
La méthode isCancelled indique si la tâche est annulée avec succès, si elle est annulée avec succès avant que la tâche ne se termine normalement, elle renvoie true.
La méthode isDone indique si la tâche est terminée, si la tâche est terminée, elle renvoie true;

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3000);
                System.out.println("线程执行中..........");
                return "执行完毕";
            }
        };
        System.out.println("线程执行之前 "+TimeFormat());
        Future<String> future = executorService.submit(callable);
        System.out.println("线程开启之后 "+TimeFormat());
        //get方法会形成阻塞
//        System.out.println("获取返回值"+ future.get());
        try {
            future.get(2,TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
            System.out.println("时间超时,舍弃。。。。");
        }
        System.out.println("获取结果之后 "+TimeFormat());
        System.out.println("线程是否结束1 "+future.isDone());
        System.out.println("线程是否完成前被取消1 "+future.isCancelled());
        Boolean oo = future.cancel(true);
        System.out.println("线程是否结束2 "+oo);
        System.out.println("线程是否结束3 "+future.isDone());
        System.out.println("线程是否完成前被取消3 "+future.isCancelled());
    }
    
    private static String TimeFormat(){
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
        return simpleDateFormat.format(now);
    }
}

résultat de l'opération:

线程执行之前 16:35:52
线程开启之后 16:35:52
java.util.concurrent.TimeoutException
	at java.util.concurrent.FutureTask.get(FutureTask.java:205)
	at CallableTest.main(CallableTest.java:24)
时间超时,舍弃。。。。
获取结果之后 16:35:55
线程是否结束1 false
线程是否完成前被取消1 false
线程是否结束2 true
线程是否结束3 true
线程是否完成前被取消3 true
线程是否结束4 false

Le délai d'expiration de TimeoutException est dû au fait que le délai d'expiration de 2 secondes doit être défini dans la méthode get () et que le thread dort pendant 3 secondes, il est donc directement ignoré et aucun résultat n'est renvoyé.

Future est une interface. Future représente le résultat d'une tâche asynchrone qui peut ne pas être terminée. Pour ce résultat, un rappel peut être ajouté pour effectuer les opérations correspondantes une fois que l'exécution de la tâche a réussi ou échoué.
Toutes les méthodes finissent par transformer runnable ou callable en un objet RunnableFuture. Cet objet RunnableFutre est une interface qui hérite à la fois de Runnable et Future.

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

Appelez ensuite la méthode exécuteur (exécutable). Enfin, un objet RunnableFuture est renvoyé. L'interface RunnableFuture a une classe d'implémentation spécifique,

public class FutureTask<V> implements RunnableFuture<V>

FutureTask implémente l'interface RunnableFuture, car nous savons que le retour final est un objet FutureTask ftask, et nous pouvons obtenir la valeur de retour de execute (task) via ftask.get ().

Quatre méthodes d'implémentation et principes du pool de threads

Insuffisance, merci de nous le signaler! ! !

Je suppose que tu aimes

Origine blog.csdn.net/qq_41587243/article/details/105935364
conseillé
Classement