Java security coding guide: thread API call rules

Thread is indispensable in the development of multithreading in Java. What rules should we pay attention to when using the API provided in thread?

Let's have a look.

Start a thread

There are two methods in thread, one is the start method and the other is the run method. Both of them can be called. What is the difference between the two?

Let's first look at the start method:

public synchronized void start() {

        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }

    private native void start0();

Start () is a synchronized method. It will call the start0 method of native, and will eventually call the run () method of thread.

We know that there are two ways to create a thread: one is to pass in a runnable, the other is to inherit the thread and override the run () method.

What happens if we call thread's run () method directly?

Let's first look at the definition of the run method:

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

By default, this target is a runnable object. If the thread is built through runnable, call thread Run () will run the contents of the run method in the current thread.

If the thread is built in its form and the run () method is not rerun, then the thread is called directly Run () will do nothing.

    public void wrongStart(){
        Runnable runnable= ()-> System.out.println("in thread running!");
        Thread thread= new Thread(runnable);
        thread.run();
    }

    public void correctStart(){
        Runnable runnable= ()-> System.out.println("in thread running!");
        Thread thread= new Thread(runnable);
        thread.start();
    }

Therefore, only the second of the above two calling methods is correct.

Do not use ThreadGroup

One of the field types in the thread is Java Lang. ThreadGroup, which is mainly used to group threads. Let's take a look at the constructor of threads:

 public Thread(ThreadGroup group,Runnable target) {
        this(group,target,"Thread-" + nextThreadNum(),0);
    }

The above constructor can pass a ThreadGroup to group threads while passing in runnable.

If ThreadGroup is not specified, it will be assigned a default default group.

What does ThreadGroup do? ThreadGroup is a method introduced in Java 1.0. It mainly operates a group of threads at one time. We can call ThreadGroup Interrupt() to interrupt the threads of the entire group at one time.

Although ThreadGroup provides many useful methods, many of them have been abandoned, such as allowthreadsuspension(), resume(), stop(), and suspend(), and many methods in ThreadGroup are non thread safe:

This method is mainly used to count the number of active threads in a ThreadGroup. This method will count the threads that have not been started and will also be affected by the system threads, so it is inaccurate.

This method copies the threads of ThreadGroup and subgroups into an array, but if the array is too small, redundant threads will be automatically ignored.

ThreadGroup itself has a stop () method to stop all threads, but stop is unsafe and has been abandoned.

So how can we safely stop many threads?

Using the executor Just shut down ().

Do not use the stop () method

We just talked about not calling the stop () method in ThreadGroup, because stop is unsafe.

Calling the stop method will immediately release all locks held by the thread and throw a ThreadDeath exception.

Because all locks are released, the state of the objects protected by these locks may be inconsistent.

There are two alternative methods. One is to use the volatile flag variable to control the loop execution of the thread:

    private volatile boolean done = false;

    public void shutDown(){
        this.done= true;
    }

    public void stopWithFlag(){

        Runnable runnable= ()->{
            while(!done){
                System.out.println("in Runnable");
            }
        };

        Thread thread= new Thread(runnable);
        thread.start();
        shutDown();
    }

Another method is to call interrupt(). Here, we should pay attention to the key points of interrupt():

Let's look at the following example:

    public static void main(String[] args)  {
        Runnable runnable= ()->{
            while (!Thread.interrupted()) {
             System.out.println("in thread");
            }
        };
        Thread thread= new Thread(runnable);
        thread.start();
        Thread.sleep(5000);
        thread.interrupt();
    }

We called Thread. in the while loop. The interrupted () method is used to determine whether the thread has been set up in the middle, and then called thread. in the main method. Interrupt() to set the interrupt, and finally the thread can be stopped correctly.

Let's take another example:

    public static void main(String[] args)  {
        Runnable runnable= ()->{
            while (!Thread.interrupted()) {
             System.out.println("in thread");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread thread= new Thread(runnable);
        thread.start();
        thread.interrupt();
    }

The difference between this example and the above example is that the sleep method is invoked in Thread, which causes Thread to be blocked, and finally satisfies the first condition, so that no terminal location will be set up. Only InterruptedException will be thrown, so the thread in this example will not be stopped, so we must pay attention to it.

Wait and await need to be called in the loop.

Why put it in the loop? Because we hope that the wait is not awakened by mistake, we need to re detect the condition after the wait is awakened.

The wrong call is placed in the if statement:

synchronized (object) {
  if (<condition does not hold>) {
    object.wait();
  }
  // Proceed when condition holds
}

The correct method is to put it in the while loop:

synchronized (object) {
  while (<condition does not hold>) {
    object.wait();
  }
  // Proceed when condition holds
}

Code for this article:

learn-java-base-9-to-20/tree/master/security

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>