java multithreading to create a thread

java multithreading to create a thread




Today, let's introduce several ways to create threads. I believe you will soon be able to say two ways after learning java, inherit the Thread class or implement the Runnable interface. But today, in addition to these two ways, we also introduce the creation methods of other two threads.

1, Inherit Thread class

First, we introduce the first method, which inherits the Thread class.

public class MyThread extends Thread {

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "  This is MyThread thread ");
		System.out.println("inherit Thread Class to implement a thread");
	}

	public MyThread(String name) {
		this.setName(name);
	}

	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName() + "  This is main thread ");
		MyThread myThread = new MyThread("myThread");
		myThread.start();
	}
}

After inheriting the Thread class, override the run method of the Thread class. And call its start method, a new Thread will be created. Here's the difference between calling the run method and calling the start method. Calling the run method is just a simple use of an object instance method and will not create a Thread. Calling the start method will notify the java virtual machine to create a new Thread and execute the run method.

To prove that we started a new thread, not in the main thread. We use thread currentThread(). Getname() gets the name of the currently executing thread and prints it on the console for comparison.

Here, if you want to verify the difference between the start method and the run method, you can put myThread Change start() to myThread Run () looks at the thread name printed out by the console.

2, Implement Runnable interface

Let's now introduce the second method, which implements the Runnable interface.

public class MyThread02 implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName() + "  This is MyThread02 thread ");
		System.out.println("inherit Thread Class to implement a thread");
	}

	
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName() + "  This is main thread ");
		MyThread02 myThread02 = new MyThread02();
		new Thread(myThread02,"myThread02").start();
	}
}

Similarly, after we implement the Runnable interface, we rewrite its run method.
However, when creating a Thread, it is slightly different. We inherit the Thread class. We can directly new the corresponding instance object and use its start method to start the Thread.
However, we found that only one run method is declared in the Runnable interface, and there is no start method. Therefore, the Thread class provides us with new construction methods, namely these two construction methods:

 public Thread(Runnable target, String name) {
        this(null, target, name, 0);
    }
 public Thread(Runnable target) {
        this(null, target, "Thread-" + nextThreadNum(), 0);
    }

We only need to pass an object that implements the Runnable interface to get a thread, and the run method of the thread is the run method after the object is rewritten. At the same time, in order to prove that we have started a new thread, we continue to use thread currentThread(). Getname() to prove

3, Implement Callable interface

Now let's focus on the Callable interface. First, let's implement the Callable interface.

public class MyThread03 implements Callable<T>{

}

At this time, we found an interface called. What does this generic type represent? Let's talk about it later. Let's go to the source code of Callable first.

package java.util.concurrent;


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

After deleting the redundant comments, I copied them and posted them here. We found that they are very similar to the Runnable interface. There is only one method, but this method is called call. The magic is that the call method is a method with a return value. Whether we inherit the Thread class or implement the Runnable interface, we all know that its run method has no return value. This return value is also unique to the Callable interface. With this return value, we can make a Thread run at the end, and we can get the result of a Thread run. This result is the generic type declared when the Callable interface is implemented.

Well, now let's declare a return value casually, and then use the Callable interface to get a thread.

import java.util.concurrent.Callable;

public class MyThread03 implements Callable<Integer>{
	
	public static final Integer i = new Integer(0);

	@Override
	public Integer call() throws Exception {
		System.out.println(Thread.currentThread().getName() +":"+ i);
		return i;
	}

	public static void main(String[] args) {
		
	}
}

We wrote this first, and then found that it was stupid. Why? Because we found that the Thread class does not provide a construction method of Callable.

Then what shall I do? At this time, we use a new class called FutureTask. Let's take a look at the FutureTask class and find that it implements an interface called RunnableFuture, which inherits the two interfaces of Runnable and future. In other words, its top layer is still a Runnable interface, which is what we often call the adapter mode in the design model. FutureTask just provides us with the construction method of Callable interface.

  public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

OK, let's go back to the code created by our thread.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyThread03 implements Callable<Integer> {

	public static final Integer i = new Integer(0);

	@Override
	public Integer call() throws Exception {
		System.out.println(Thread.currentThread().getName() +":"+ i);
		return i;
	}

	public static void main(String[] args) {
		MyThread03 myThread03 = new MyThread03();
		System.out.println(Thread.currentThread().getName()+"I am main thread ");
		FutureTask<Integer> futureTask = new FutureTask<Integer>(myThread03);
		new Thread(futureTask).start();
	}
}

We instantiate the object that implements the Callable interface and use it to instantiate FutureTask. Use FutureTask that inherits the Runnable interface to instantiate the thread and view the console print results.

Here are just a few methods of FutureTask. We know that the method difference between Callable interface and Runnable interface lies in the return value. So how do we get this return value? We need to call the get method of FutureTask.

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

    /**
     * @throws CancellationException {@inheritDoc}
     */
    public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }

FutureTask provides us with two ways to get. One is get without parameters, that is, when a thread gets the return value, if the call method has not been executed, the thread falls into a blocking state and waits for the call method to be executed. The other is to take a waiting time parameter, that is, I'll wait for you to call the method for a period of time. If you execute it within this period of time, I'll continue to execute it. If you fail to execute well beyond this time, I will throw a TimeoutException.

Next, let's modify the code to reflect these two methods. The first is the method without parameters

public class MyThread03 implements Callable<Integer> {

	public static final Integer i = new Integer(0);

	@Override
	public Integer call() throws Exception {
		System.out.println(Thread.currentThread().getName() +":"+ i);
		Thread.sleep(3000);
		return i;
	}

	public static void main(String[] args) {
		MyThread03 myThread03 = new MyThread03();
		System.out.println(Thread.currentThread().getName()+"I am main thread ");
		FutureTask<Integer> futureTask = new FutureTask<Integer>(myThread03);
		new Thread(futureTask).start();
		try {
			System.out.println(futureTask.get());
		} catch (InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"I am main thread ");
	}
}

We let the call method sleep for 3 seconds to simulate the time occupied by business logic. Then call the get method in the main method, and print the information after calling the get method. Three seconds after the call method is executed, the return value of the get method and the subsequent information of the main method are printed out. In other words, after calling get, the main method falls into a wait, and the call method will not continue until the call method is executed.

Then let's experiment with the second method, the method with timeout parameter.

public class MyThread03 implements Callable<Integer> {

	public static final Integer i = new Integer(0);

	@Override
	public Integer call() throws Exception {
		System.out.println(Thread.currentThread().getName() + ":" + i);
		Thread.sleep(3000);
		return i;
	}

	public static void main(String[] args) {
		MyThread03 myThread03 = new MyThread03();
		System.out.println(Thread.currentThread().getName() + "I am main thread ");
		FutureTask<Integer> futureTask = new FutureTask<Integer>(myThread03);
		new Thread(futureTask).start();
		try {
			System.out.println(futureTask.get(1, TimeUnit.SECONDS));
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "I am main thread ");
//		while (futureTask.isDone()) {
//			try {
//				futureTask.get();
//			} catch (InterruptedException | ExecutionException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//		}

	}
}

After running, it is found that the console does not print the return value of the call method correctly, and prints the TimeoutException from catch. It indicates that the main thread finds that the call method is not completed after waiting for 1 second, so it throws an exception.

Callable interface, that's all. For more callable information, you can read the source code of FutureTask to understand it. It's not difficult.

4, Get from thread pool

. . . . . . . I can't write today. I'll write it another day. Ha ha ha

Tags: Java Multithreading

Posted by ysu on Tue, 03 May 2022 02:23:37 +0300