スレッドスレッドを作成する4つの方法、実行可能、呼び出し可能、およびExecutorService

スレッドを作成する4つの方法


1.Threadクラスを継承します。2。Runnableクラスを実装します。3。Callableクラスを
実装し
ます。4。スレッドプールを介してスレッドを作成します。待機状態のすべてのスレッドが格納されるスレッドキューが提供されます。余分なオーバーヘッドの作成と破壊を避け、応答速度を向上させます

アーキテクチャ:
java.util.concurrent.Executor:スレッドの使用とスケジューリングを担当するルートインターフェイス
| –ExecutorServiceサブインターフェイス:
スレッドプールのメインインターフェイス| –ThreadPoolExecutorスレッドプールの実装クラス
| –ScheduledExecutorServiceサブインターフェイス:スレッドのスケジューリングを担当
| -ScheduledThreadPoolExecutor:ThreadPoolExecutorを継承し、ScheduledExecutorServiceを実装します*

ツール:Executors
ExecutorService newFixedThreadPool():固定サイズのスレッドプールを作成します
ExecutorService newCachedThreadPool():スレッドプールをキャッシュします。スレッドプールの数は固定されておらず、必要に応じて自動的に変更できます。
ExecutorService newSingleThreadExecutor():シングルスレッドプールを作成します。スレッドプールにはスレッドが1つだけあり
ます。ScheduledExecutorServicenewScheduledThreadPool():タスクを遅延または時間指定で実行できる固定サイズのスレッドを作成します。

詳細は次のとおりです。

1つは、Threadクラスを継承する

Threadクラスを継承してスレッドを作成する手順は次のとおりです。
(1)は、run()メソッドの中に完了することがrun()メソッドを書き換え、Threadクラスを継承するクラスを作成し、タスクのコードを書きます。
( 2)ThreadクラスObjectのサブクラスを作成します。
(3)オブジェクトのstart()メソッドを呼び出します。start()メソッドは、最初にスレッドを開始してから、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());
            }
        }
    }
 }

スレッド修飾子、戻り値の型、メソッド、および説明:

修饰符、返回类型、方法和说明
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()
向调度程序提示当前线程愿意放弃当前使用的处理器。

次に、Runnableクラスを実装します

スレッドを作成するのRunnableクラスを実装する手順は:
(1)run()メソッド内に完了することがrun()メソッドを書き換え、Runnableをクラスを実装するクラスを作成し、タスクのコードを記述し、
( 2)RunnableクラスObjectのサブクラスを作成します;
(3)最初にThreadをインスタンス化し、独自のMyRunnableインスタンスを渡す必要があります。
(4)オブジェクトのstart()メソッドを呼び出します。start ()メソッドはスレッドを開始することを意味します。最初に、次に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+"  ");
			}
		}
	}

動作結果:

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

既知のすべてのサブインターフェイス:
RunnableFuture、RunnableScheduledFutureV-
このFutureのgetメソッドによって返される結果タイプ

ExecutorServiceのdexecutor.execute(new RunnableTask1())によってスレッドを直接開始することもできます。

第三に、Callableクラスを実装します

Callableクラスを実装してスレッドを作成する手順は次のとおりです。
(1)Callableクラスを実装するクラスを作成し、run()メソッドを書き直し、完了するタスクのコードをrun()メソッドに書き込みます。戻り値を持つスレッドを持つことができます;
(2)Callableクラスのサブクラスのオブジェクトを作成します;
(3)最初にFutureTaskをインスタンス化し、独自のmyCallableインスタンスを渡す
必要があります(4)最初にスレッドをインスタンス化する必要があります独自のFutureTaskインスタンスを渡します
(5)オブジェクトのstart()メソッドを呼び出します。start ()メソッドは、最初にスレッドを開始してから、run()メソッドを呼び出すことを意味します。

利点:FutureTaskの
get()メソッドを呼び出して、戻り値取得できます。このメソッドはブロックしているため、スレッドが完了するのを待機しており、時間がかかる場合があります。そのため、タイムアウト期間を設定する必要がある場合があります。
get(long var1、TimeUnit var3)このメソッドの最初のパラメーターは長整数で、2番目のパラメーターはユニット
キャンセル(boolean mayInterruptIfRunning)です。タスクをキャンセルし、
trueを渡します成功した場合、実行中のタスクはキャンセルされます。 trueを返し、失敗falseを返します
。falseを渡すと、開始されていないタスクのみがキャンセルされ、実行中のタスクは正常に実行されます。
isCancelledメソッドは、タスクが正常にキャンセルされたかどうかを示します。タスクが正常に完了する前に正常にキャンセルされた場合は、trueを返します。
isDoneメソッドは、タスクが完了したかどうかを示します。タスクが完了した場合は、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;
        }
    }
}

動作結果:

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

第四に、スレッドプールを作成する方法

スレッドプール作成の手順は
次のとおりです。(1)最初にスレッドプールのExecutorServiceを作成し、
(2)Callableオブジェクトをインスタンス化し、return値を持つことができるcall()メソッドを書き直します。
(3)executorService.submitを呼び出します。(呼び出し可能))このメソッドは、マルチスレッド実行の結果を受け取るために使用できるFutureオブジェクトを返します。
または、executorService.execute(myRunnale)メソッドはFutureオブジェクトを返します。これは、複数のスレッドの実行結果を受け取るために使用できます。

利点:Futureの
get()メソッドを呼び出して戻り値取得できます。このメソッドはブロックしているため、スレッドが完了するのを待機しており、時間がかかる場合があります。そのため、タイムアウト期間を設定する必要がある場合があります。
get(long var1、TimeUnit var3)このメソッドの最初のパラメーターは長整数で、2番目のパラメーターはユニット
キャンセル(boolean mayInterruptIfRunning)です。タスクをキャンセルし、
trueを渡します成功した場合、実行中のタスクはキャンセルされます。 trueを返し、失敗falseを返します
。falseを渡すと、開始されていないタスクのみがキャンセルされ、実行中のタスクは正常に実行されます。
isCancelledメソッドは、タスクが正常にキャンセルされたかどうかを示します。タスクが正常に完了する前に正常にキャンセルされた場合は、trueを返します。
isDoneメソッドは、タスクが完了したかどうかを示します。タスクが完了した場合は、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);
    }
}

動作結果:

线程执行之前 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

TimeoutExceptionのタイムアウトは、get()メソッドで2秒のタイムアウト期間を設定する必要があり、スレッドが3秒間スリープするため、スレッドは直接破棄され、結果は返されません。

Futureはインターフェースです。Futureは、完了しない可能性のある非同期タスクの結果を表します。この結果の場合、タスクの実行が成功または失敗した後に、コールバックを追加して対応する操作を実行できます。
すべてのメソッドは、最終的にrunnableまたはcallableをRunnableFutureオブジェクトに変換します。このRunnableFutreオブジェクトは、RunnableとFutureの両方を継承するインターフェイスです。

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

次に、executor(runnable)メソッドを呼び出します。最後に、RunnableFutureオブジェクトが返されます。インターフェイスRunnableFutureには、特定の実装クラスがあります。

public class FutureTask<V> implements RunnableFuture<V>

FutureTaskはRunnableFutureインターフェースを実装します。これは、最終的な戻り値がFutureTaskオブジェクトのftaskであることがわかっており、ftask.get()を介してexecute(task)の戻り値を取得できるためです。

スレッドプールの4つの実装方法と原則

不備、アドバイスしてください!

おすすめ

転載: blog.csdn.net/qq_41587243/article/details/105935364