Basic threading mechanism – Java programming idea

Concurrent programming allows us to divide programs into separate, independently running tasks. By using multithreading, each of these individual personas (also known as subtasks) is driven by the thread of execution.

A thread is a single flow of sequential control in a process; therefore, a single process can have multiple tasks executing concurrently.

When threads are used, the CPU allocates its occupied time to each task in turn.

One of the great benefits of threading is that it takes you out of the hierarchy, meaning Diamante doesn’t have to know whether it’s running on a machine with one or more cpus.

21.2.1 Defining tasks

Threads can drive tasks, and here we implement the Runnable interface to define tasks. To implement threading behavior, you must explicitly attach a task to the thread.

Thread.yield()

This method is a suggestion to the thread scheduler, which states: “I have completed the most important part of the declaration cycle, and now is a good time to switch to other tasks for some time.”

Thread scheduler: Part of the Java threading mechanism that transfers CPU from one thread to another.

21.2.2 Thread class

The traditional way to turn a Runnable object into a work task is to submit it to a Thread constructor.

Call the Start () method of the Thread object to perform the necessary initialization for the Thread, and then call the Run () method of Runnable to start the task in the new Thread.

Any thread can start another thread.

Thread scheduling is nondeterministic.

When using a normal object, this is a reference to it for the garbage collection, but when using Thread, the situation is different. Each Thread “registers” itself, so there is indeed a reference to it, and the garbage collector cannot clean it up until its task exits its run() and dies.

A thread creates a separate thread of execution that continues after the call to start() is complete.

21.2.3 using Executor

The Executor in the java.util.concurrent package of Java SE5 will manage Thread objects for you, simplifying concurrent programming.

Executor allows you to manage the execution of asynchronous tasks without explicitly managing the thread lifecycle. Executor is the preferred method of starting tasks in Java SE5/6.

The call to the ExecutorService#shotdown() method prevents new tasks from being submitted to the Executor, and the current task will continue to execute all tasks submitted before shotdown() is called. This program will exit as soon as all the Executor tasks are complete.

FixedThreadPool

A FixedThreadPool uses a limited set of threads to execute the submitted task. With FixedThreadPool, you can pre-execute costly county assignments once, thus limiting the number of threads. This saves time because you don’t have to pay the overhead of creating a thread for every task.

Note that in any thread pool, existing threads are automatically reused whenever possible.

CachedThreadPool

CachedThreadPool typically creates as many threads as it needs during program execution, and then stops creating new threads when it reclaims old ones, so it is a reasonable Executor’s first choice. Switch to FixedThreadPool only if this approach causes problems.

SingleThreadExecutor

SingleThreadExecutor is like a FixedThreadPool with one thread. This is useful for anything (long-lived tasks) that you want to run continuously in another thread.

If you want to SingleThreadExecutor to submit multiple tasks, these tasks will be queued, each task will run before the next task starts, and all tasks will use the same thread.

SingleThreadExecutor serializes all tasks submitted to it and maintains its own (hidden) queue of suspended tasks.

SingleThreadExecutor ensures that only one task is running in any thread at any time.

21.2.4 Generating the return value — Callable from the Task

Runnable is a separate task that performs work, but it does not withdraw any of its duties. If you want the task to return a value upon completion, implement the Callable interface instead of the Runnable interface. Callable, introduced in Java SE5, is a generic type with parameter types, whose type parameters represent values returned from the call() method instead of run(), and which must be called using the executorService.submit () method.

The submit() method produces a Future object that is parameterized with the specific type of result that Callable returns. You can use the isDone() method to check if the Future has been completed. When the task is complete, it has a result that you can call the get() method to get. You can also call get() without isDone() checking, in which case get() blocks until the result is ready. You can also call get() with timeout before trying to call get() to get the result, or isDone() to see if the task is complete.

21.2.5 dormant — Thread. Sleep ()

A simple way to influence the behavior of a task is to call sleep(), which causes the task to abort for a given amount of time.

The call to sleep() can run InterruptedException, and it can be caught in Run (). Because exceptions cannot be propagated back to main() across threads, you must handle all exceptions raised within the task locally.

21.2.6 priority

The priority of a thread communicates the importance of that thread to the scheduler. Although the order in which the CPU processes the existing thread set is uncertain, the scheduler will prefer the highest line to execute first. However, this does not mean that threads with lower priority will not execute (that is, priority does not cause deadlocks). Lower priority threads simply execute less frequently.

Most of the time, threads should run at their default priority. It is usually a mistake for views to manipulate thread priorities.

You can always use getPriority() to read the priority of an existing thread, and you can change it at any time by using setPriority().

Note that the priorities are set at the beginning of run(), and there is no benefit in setting them in the constructor because the Executor has not started executing at this point.

The JDK has 10 priorities, but it doesn’t map well to most operating systems. The only portable method to adjust priorities is MAX_PRIORITY, NORM_PRIORITY, and MIN_PRIORITY.

volatile

Variables are decorated with volatile in an effort to ensure that no compiler optimizations are made.

Thread.toString()

The thread.toString () method prints the name of the Thread, its priority, and the “Thread group” to which it belongs. You can set the name yourself via the constructor.

Thread.currentThread()

You can get a reference to the Thread object inside a task by calling Thread.currentThread().

21.2.7 concessions – Thread. The yield ()

If you know that the run() method has done enough work to allow another thread to use the CPU, you can use yield() to give a hint (but this is only a hint, and there is no guarantee that it will be taken).

When yield() is called, you are also suggesting that other threads of the same priority should run.

In general, yield() should not be relied on for any significant control or when tuning applications. In fact, yield() is often misused.

21.2.8 Background Threads: daemon

A daemon thread is a thread that provides a communication service in the background while a program is running and is not an integral part of the program.

When all non-background threads terminate, the program terminates, killing all background threads in the process. Conversely, the program does not terminate as long as any non-background threads are running.

The setDaemon() method must be called before the thread is started to set it up as a background thread.

Each static ExecutorService creation method is overridden to accept a ThreadFactory object, which will be used to create new threads. You can customize the attributes (background, priority, name) of threads created by Executor by writing a custom ThreadFactory.

You can determine if a thread is a background thread by calling the isDaemon() method. If it is a background thread, any threads it creates will be automatically set as background threads.

A background thread terminates its run() method without executing a finally statement.
public class DaemonsDontRunFinally {

    public static void main(String[] args) {
        Thread t = new Thread(new ADaemon());
        t.setDaemon(true);
        t.start();
    }

}

class ADaemon implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("Starting ADaemon");
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            System.out.println("Exiting via InterruptedException");
        } finally {
            System.out.println("This should always run?"); }}}Copy the code

When you run this program you will see that the finally clause does not execute, but if you comment out the call to setDaemon() you will see that the finally clause will execute.

This behavior is correct, even if you don’t want it based on previous promises to Finally, but it will still be the case. The background scene terminates “suddenly” when the last background thread terminates. So as soon as main() exits, the JVM shuts down all background processes immediately, without any confirmation you’d expect. So you can’t close background threads in an elegant way, so they’re hardly a good idea.

Non-background executors are usually a better approach because all tasks controlled by executors can be shut down at the same time. In this case, the shutdown will be performed in an orderly manner.

21.2.9 Encoding variants

1, inherit Thread, override run method, call start() method in constructor to start Thread.

The Thread object is given a specific name by calling the appropriate Thread constructor, which can be obtained from toString() using getName().

2. Self-managed Runnable Implements the Runnable interface, implements the run method, initializes a Thread, and calls Thread#start() in the constructor.

Notice that start() is called in the constructor. You should be aware that starting a thread in a constructor can be problematic because another task may start execution before the constructor ends, which means that the task is able to access objects in an unstable state. This is another reason to prefer executors to explicitly creating Thread objects.

3. Threading code is hidden in an inner class. ① Define a member inner class that inherits Thread, overrides run, and executes the start() method in the constructor of the inner class. ② Anonymous inner class inherits Thread class, implementation is the same as above. ③ Define a member inner class that implements the Runnable interface, overrides the run method, and executes the start() method in the constructor of the inner class. ④ Anonymous inner class integrates Runnable interface.

Execute methods that define tasks and start threads in separate methods. The anonymous inner class for Thread is used here.

21.2.10 term

In Java, you can choose how to implement concurrent programming.

There is a difference between the task to be executed and the Thread that drives it, and this difference is particularly noticeable in the Java class library because you have no control over the Thread class (this isolation is even more noticeable when using an executor, which handles Thread creation and management for you).

You create tasks and somehow attach a thread to the task so that the thread can drive the task.

In Java, the Thread class does nothing on its own; it just drives the task assigned to it, but threading studies have always used languages like “threads do this or that action.”

Java’s threading mechanism is based on the P-threading approach from the foundation of C, which is a way that you have to dig deep and understand everything in detail.

21.2.11 Adding a thread — Join, Interrupt

A thread can call the join() method on top of another thread, which has the effect of waiting a certain amount of time for the other threads to resume execution.

When the thread is suspended, T.isalive () returns false.

You can also call join() with a supermarket argument (in milliseconds, milliseconds and nanoseconds) so that if the target thread has not finished by the end of that time, the join() method always returns.

Calls to the join() method can be interrupted by calling the interrupt() method on the calling thread, using the try-catch clause.

You can use the isInterrupted() method to return whether the thread was interrupted. When a thread calls the interrupt() method, it is given a flag indicating that it has been interrupted. However, the flag is cleaned up when the exception is caught, so in the catch clause, the flag is always false when the exception is caught.

21.2.13 thread group

A thread group holds a collection of threads.

21.2.14 Catching thread exceptions

Because of the nature of threads, you cannot catch exceptions that escape from the thread. Once an exception escapes the task’s run() method, it is propagated outward to the console, unless you take special steps to catch such a bad exception.

We throw an exception in the run method, and then we put the thread of execution code in a try-catch block, and you see that the try-catch doesn’t work.

To solve this problem, we need to change the way Executor generates threads. Thread. UncaughtExceptionHandler is the new interface in Java SE5, it allows you to on each Thread is attached to an exception handler. Thread. UncaughtExceptionHandler. UncaughtException () in the Thread near death due to an uncaught exception is invoked.

We create a ThreadFactory, it will be in each of the newly created Thread object attached to a Thread. UncaughtExceptionHandler. We just pass this factory to Executor.

If you need to use the same exception handler everywhere in your code, you can set a static and in the Thread class and make this handler the default uncaught exception handler.

Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
Copy the code

This handler is called only if no thread-specific uncaught exception handler exists.

System checks a proprietary version, if not found, then check to see if the thread group has its around uncaughtException () method, if no, call defaultUncaughtExceptionHandler again.