Java-JUC (6): 4 ways to create threads

There are 4 ways to create threads in Java:

Java uses the Thread class to represent threads, and all thread objects must be instances of the Thread class or its subclasses. Java can create threads in four ways:

1) Inherit the Thread class to create a thread;

2) Implement the Runnable interface to create threads;

3) Implement the Callable interface and create a Thread thread through the FutureTask wrapper;

4) Use ExecutorService, Callable (or Runnable), and Future to implement the thread that returns the result.

Next, these four methods are introduced in detail and their usage:

1) Inherit the Thread class to create a thread

The Thread class is essentially an instance that implements the Runnable interface, representing an instance of a thread. The only way to start a thread is through the start() instance method of the Thread class. The start() method is a native method that will start a new thread and execute the run() method. It is very simple to implement multi-threading in this way. You can directly extend Thread through your own class and override the run() method to start a new thread and execute your own defined run() method.

E.g:

/**
 * no return value
 */
class MyThread extends Thread {
    CountDownLatch countDownLatch;

    public MyThread(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":my thread ");
        } catch (InterruptedException e) {
            e.printStackTrace ();
        } finally {
            countDownLatch.countDown();
        }
    }
}

main call:

    public  static  void main(String[] args) {
         // The first: use the extends Thread method 
        CountDownLatch countDownLatch1 = new CountDownLatch(2 );
         for ( int i = 0; i < 2; i++ ) {
            MyThread myThread1 = new MyThread(countDownLatch1);
            myThread1.start();
        }

        try {
            countDownLatch1.await();
            System.out.println("thread complete...");
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }

2) Implement the Runnable interface to create a thread

If your own class already extends another class, you cannot directly extend Thread. In this case, you can implement a Runnable interface, as follows:

/**
 * no return value
 */
class MyRunnable implements Runnable {
    CountDownLatch countDownLatch;

    public MyRunnable(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + ":my runnable");
        } catch (InterruptedException e) {
            e.printStackTrace ();
        } finally {
            countDownLatch.countDown();
        }
    }
}

In order to start MyRunnable, you need to first instantiate a Thread and pass in your own instance of MyRunnable:

    public  static  void main(String[] args) {
         // Second: use implements Runnable 
        CountDownLatch countDownLatch2 = new CountDownLatch(2 );
        MyRunnable myRunnable = new MyRunnable(countDownLatch2);
        for (int i = 0; i < 2; i++) {
            new Thread(myRunnable).start();
        }

        try {
            countDownLatch2.await();
            System.out.println("runnable complete...");
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }

In fact, when a Runnable target parameter is passed to Thread, Thread's run() method will call target.run(), refer to the JDK source code:

public void run() {  
  if (target != null) {  
   target.run();  
  }  
}  

3) Implement the Callable interface and create a Thread thread through the FutureTask wrapper

The Callable interface (which also has only one method) is defined as follows:   

public interface Callable<V>   { 
  V call() throws Exception;   
}

If your own class has already extended another class, you cannot directly extend Thread. In this case, you can implement a Callable interface (which has a return value), as follows:

/**
 * with return value
 */
class MyCallable implements Callable<Integer> {
    CountDownLatch countDownLatch;

    public MyCallable(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    public Integer call() throws Exception {
        try {
            Thread.sleep(2000);

            int sum = 0;
            for (int i = 0; i <= 100; i++) {
                sum += i;
            }

            System.out.println(Thread.currentThread().getName() + ":my callable");

            return sum;
        } finally {
            countDownLatch.countDown();
        }
    }
}

Unlike the Runnable interface, the Callable interface provides a call() method as a thread execution body, and the call() method is more powerful than the run() method.

1) The call() method can have a return value

2) The call() method can declare to throw an exception

Java5 provides the Future interface to represent the return value of the call() method in the Callable interface, and provides an implementation class FutureTask for the Future interface. This implementation class implements both the Future interface and the Runnable interface, so it can be used as a Thread class. target. Several public methods are defined in the Future interface to control its associated Callable task.

boolean cancel( boolean mayInterruptIfRunning): // The view cancels the Callable task associated with the Future 
V get(): // Return to call() in the Callable // The return value of the method, calling this method will cause the program to block and must wait until the child thread After the end, the return value 
V get( long timeout, TimeUnit unit): // Return the return value of the call() method in Callable, block the timeout time at most, and throw TimeoutException if it does not return after the specified time 
boolean isDone(); // If the Callable task is completed, return True 
boolean isCancelled(); // If the Callable task is cancelled before the normal completion of the callable task, return True

After introducing the relevant concepts, the steps to create and start a thread with a return value are as follows:

1) Create an implementation class of the Callable interface, implement the call() method, and then create an instance of the implementation class (from java8, you can directly use Lambda expressions to create Callable objects).

2) Use the FutureTask class to wrap the Callable object, which encapsulates the return value of the call() method of the Callable object

3) Use the FutureTask object as the target of the Thread object to create and start the thread (because the FutureTask implements the Runnable interface)

4) Call the get() method of the FutureTask object to obtain the return value after the execution of the child thread ends

main call:

    public  static  void main(String[] args) {
         // The third: use implements Callable method, with return value 
        List<FutureTask<Integer>> resultItems1 = new ArrayList<FutureTask<Integer>> ();
        CountDownLatch countDownLatch3 = new CountDownLatch(2);
        for (int i = 0; i < 2; i++) {
            MyCallable myCallable = new MyCallable(countDownLatch3);
            FutureTask<Integer> futureTask = new FutureTask<Integer>(myCallable);
            new Thread(futureTask).start();
            resultItems1.add(futureTask);
        }

        try {
            countDownLatch3.await();
            Iterator<FutureTask<Integer>> iterator = resultItems1.iterator();
            while (iterator.hasNext()) {
                try {
                    System.out.println(iterator.next().get());
                } catch (ExecutionException e) {
                    e.printStackTrace ();
                }
            }
            System.out.println("callable complete...");
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }

4) Use ExecutorService, Callable (or Runnable), and Future to implement the thread that returns the result

The Executors class provides a series of factory methods for creating thread pools, and the returned thread pools all implement the ExecutorService interface:

public  static ExecutorService newFixedThreadPool( int nThreads) ; // Create a thread pool with a fixed number of threads. 
public  static ExecutorService newCachedThreadPool(); // Create a cacheable thread pool, calling execute will reuse previously constructed threads (if threads are available). If no existing thread is available, a new thread is created and added to the pool. Threads that have not been used for 60 seconds are terminated and removed from the cache. 
public  static ExecutorService newSingleThreadExecutor(); // Create a single-threaded Executor. 
public  static ScheduledExecutorService newScheduledThreadPool( int corePoolSize); // Create a thread pool that supports timing and periodic task execution, which can be used to replace the Timer class in most cases.

ExecutoreService provides the submit() method, which passes a Callable, or Runnable, and returns a Future. If the Executor background thread pool has not completed the calculation of the Callable, this call returns the get() method of the Future object, which will block until the calculation is completed.

The following takes MyCallable as an example to show the specific usage (MyCallable is the same as the definition in 3):

    public  static  void main(String[] args) {
         // The fourth method: use the thread pool method
         // Accept the return parameter 
        List<Future> resultItems2 = new ArrayList<Future> ();
         // Initialize 5 threads for the thread pool 
        ExecutorService executorService = Executors.newFixedThreadPool(5 );
        CountDownLatch countDownLatch4 = new CountDownLatch(10);

        for (int i = 0; i < 10; i++) {
            MyCallable myCallable = new MyCallable(countDownLatch4);
            Future result = executorService.submit(myCallable);
            resultItems2.add(result);
        }

        // Wait for the task allocated in the thread pool to complete before closing (no new threads are allowed to join after closing, but it will not wait for the thread to end), and executorService.shutdownNow(); is closed immediately regardless of whether it is in the thread pool or not There are other outstanding threads. 
        executorService.shutdown();
         try {
            countDownLatch4.await();            
            Iterator<Future> iterator = resultItems2.iterator();
            while (iterator.hasNext()) {
                try {
                    System.out.println(iterator.next().get());
                } catch (ExecutionException e) {
                    e.printStackTrace ();
                }
            }
            System.out.println("callable complete...");
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324725831&siteId=291194637