Three ways to create threads

3.ways to create threads

3.ways to create threads

1. Inherit the Thread class

public class ThreadTest01 extends Thread {

    @Override
    public void  run () {
        for  (int i = 0; i <10; i++) {
            System.out.println( "run--->"  + i);
        }
    }

    public static void main(String[] args) {
        Thread thread = new ThreadTest01();
        thread.start();

        for  (int i = 0; i <10; i++) {
            System.out.println( "main====>"  + i);
        }
    }
}
Copy code

Copying code is not recommended to avoid the limitations of OOP single inheritance

2. Implement the Runnable interface

public class ThreadTest02 implements Runnable {
    @Override
    public void  run () {
        for  (int i = 0; i <10; i++) {
            System.out.println( "run--->"  + i);
        }
    }

    public static void main(String[] args) {
        ThreadTest02 t = new ThreadTest02();
        Thread thread = new Thread(t);
        thread.start();

        for  (int i = 0; i <10; i++) {
            System.out.println ( "main====>"  + i);
        }
    }
}
Copy code

Copy code recommended to use: avoid the limitations of single inheritance, flexible and convenient, and convenient for the same object to be used by multiple threads. Use anonymous inner classes to simplify the code:

interface Test {
    void fun();
}

public class AnonymousClassesTest {
    public static void main(String[] args) {
  //Anonymous inner class
  Test  test  = new  Test () {
            public void  fun () {
                System.out.println( " Anonymous inner class" );
            }
        };
        
        test.fun();//Output: anonymous inner class

  //Use anonymous inner class to create thread
  new Thread(new  Runnable () {
            @Override
            public void  run () {
                System.out. println( "abc" );
            }
        .}) Start ();//ABC
}
Copy code

Copy the code Use lambda expressions to simplify the code: Any interface, if it contains only one abstract method, then it is a functional interface. For functional interfaces, we can create objects of the interface through lambda expressions.

interface Test {
    void fun();
}

public class LambdaTest {
    public static void main(String[] args) {
     //lambda expression    
     //The content in curly braces is equivalent to rewriting the method in the interface, when the code is only one line, You can remove the curly braces
        test  = () -> {
            System.out.println( "i like lambda" );
        };

        test.fun();//Output: i like lambda
        
        //Use lambda expressions to create threads
  new Thread( () -> System.out.println ( "ABC" )) .start ();//ABC
  
        
    }
}
copy the code

Copy the code 3. Implement the Callable interface

public class ThreadTest04 implements Callable<String> {
    @Override
    public String call() throws Exception {

        return  "Return value" ;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> c1 = new ThreadTest04( );
        Callable<String> c2 = new ThreadTest04();
        Callable<String> c3 = new ThreadTest04();

        //Create execution service
        ExecutorService ser = Executors.newFixedThreadPool(3);

        //Submit for execution
        Future<String> f1 = ser .submit(c1);
        Future<String> f2 = ser.submit(c2);
        Future<String> f3 = ser.submit(c3);

        //Get the result
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());

        //Shut down the service
        ser.shutdown();
    }
}
Copy code

The priority of the copy code thread In the Java thread, the priority is controlled by an integer member variable priority. The priority is from low to high from 1 to 10, and the default priority is 5. The priority can be set by setPriority(int). High-priority threads are allocated more time slices than low-priority threads. But thread priority cannot be used as a dependency on the correctness of the program. 6 states of java thread

NEW: the initial state, the thread is constructed, but the start() method has not been called. RUNNABLE: the running state, the Java thread refers to the ready and running states in the operating system as "running". BLOCKED: the blocked state, which means the thread Blocked in the lock WAITING: indicates that the thread is in a waiting state. Entering this state indicates that the current thread needs to wait for other threads to make some specific actions (notification or interruption). TIME_WAITING: Timeout waiting state. This state is different from WAITING. It can be in a specified time Self-returned TERMINATED: Terminated state, indicating that the current thread has completed execution

The blocking state is the state when the thread is blocked when it enters the method or code block modified by the synchronized keyword (acquisition of the lock), but the thread blocked in the Lock interface in the java.concurrent package is in the waiting state, because the Lock in the java.concurrent package The interface uses the relevant methods in the LockSupport class for the implementation of blocking. Daemon thread Daemon (daemon thread) is a supporting thread because it is mainly used for background scheduling and supporting work in the active program. This means that when there are no non-Daemon threads in a Java virtual machine, the Java virtual machine will exit. Therefore, when building a Daemon thread, you cannot rely on the content in the finally block to ensure that the logic of closing or cleaning up resources is executed, because the content in the finally block may not necessarily be executed. You can call setDaemonn(true) (the default parameter is false) to set the thread as a Daemon thread.

public class TestDaemon {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyDaemon(),  "Daemon thread" );
        thread.setDaemon( true );
        thread.start();
    }
}

class MyDaemon implements Runnable {

    @Override
    public void  run () {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println( "I am a daemon thread" );
        }
    }
}
Copy code

Copy the code and execute the above code and you will find that there is no printing. Interrupting a thread will automatically end after its execution, and it will end early if an exception occurs during operation. By calling the interrupt() of a thread to interrupt the thread, if the thread is blocked, waiting or waiting for a timeout, then an InterruptedException will be thrown, thereby ending the thread early. However, I/O blocking and synchronized lock blocking cannot be interrupted. The thread uses the method isInterrupted() to determine whether it is interrupted. If the thread is already in the terminated state, even if the thread has been interrupted, the return result of the method is still false.

public class Interrupted {
    public static void main(String[] args) throws InterruptedException {
        //sleepThread keeps trying to sleep
        Thread sleepThread = new Thread(new SleepRunner(),  "sleepThread" );
        //BusyThread keeps running
        Thread busyThread = new Thread (new BusyRunner(),  "busyThread" );
        sleepThread.setDaemon( true );
        busyThread.setDaemon( true );
        sleepThread.start();
        busyThread.start();

        //Sleep for 5 seconds, let sleepThread and BusyThread run
        Thread fully .sleep(5000);
        sleepThread.interrupt();         System.out.println(
        busyThread.interrupt();

"sleepThread interrupted is "  + sleepThread.isInterrupted());//  false
        System.out.println( "busyThread interrupted is"  + busyThread.isInterrupted());//  true

        //Prevent sleepThread and BusyThread immediately withdraw
        Thread.sleep (2000);
    }
}

copy the code
class SleepRunner implements Runnable {

    @Override
    public void  run () {
        while  ( true ) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class BusyRunner implements Runnable {

    @ override
    public void  RUN () {
        the while  ( to true ) {
        }
    }
}
copy the code

Copy the code running results: sleepThread interrupted is false busyThread interrupted is true java.lang.InterruptedException: sleep interrupted sleepThread is in a timeout waiting state, interrupted will throw an exception and terminate the thread early. At this time, it is judged whether it is interrupted and the return is false. Waiting/Notification Mechanism One thread modifies the value of an object, and another thread senses the change, and then performs the corresponding operation. The whole process starts in one thread, and the final execution is another thread. The former is a producer and the latter is a consumer. This model isolates "what" and "how", achieves decoupling at the functional level, and has good scalability in the architecture. Java implements similar functions through the wait/notify mechanism. Waiting/notifying related methods are available for any Java object, because these methods are defined on the superclass java.lang.Object of all objects, and the methods are as follows:

notify(): notify a thread waiting on the object to return from the wait() method, and the premise of return is that the thread has acquired the object's lock notifyAll(): notify all threads waiting on the object wait() : The thread that calls this method enters the WAITING state, and returns only when it waits for another thread's notification or is interrupted. It should be noted that after calling the wait() method, the lock of the object will be released. wait(long): Over a period of time, the parameter here is milliseconds, that is, to wait for up to n milliseconds, if there is no notification, it will time out and return. wait(long, int): For more fine-grained control of the timeout period, it can reach nanoseconds.

The wait/notification mechanism means that a thread A calls the wait() method of object O to enter the waiting state, and another thread B calls the notify() or notifyAll() method of object O. Thread A receives the notification from the object O's wait() method returns, and then performs subsequent operations.

import java.text.SimpleDateFormat;
import java.util.Date;

public class WaitNotify {
    static Object lock = new Object();
    static boolean flag =  true ;

    public static void main(String[] args) throws InterruptedException {
        Thread waitThread = new Thread(new Wait(),  "waitThread" );
        waitThread.start();
        Thread.sleep(1000);
        Thread notifyThread = new Thread(new Notify(),  "notifyThread" );
        notifyThread.start();
    }

    static class Wait implements Runnable {
        @Override
        public void  run () {
            synchronized (lock) {
                //When the condition is not met, continue to wait and release the lock at the same time
                while  (flag) {
                    try {
                        System.out.println(Thread.currentThread().getName() +  "flag is true wait @"  +
                                new SimpleDateFormat( "HH:mm:ss" ).format(new Date()));
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //The conditions are met and the work is completed
                System. out.println(Thread.currentThread().getName() + "flag is false running @ "  +
                        new SimpleDateFormat( "HH:mm:ss" ).format(new Date()));
            }
        }
    }

    static class Notify implements Runnable {
        @Override
        public void  run () {
            synchronized (lock) {
                //Acquire the lock of the lock, and then notify, the lock of the lock will not be released
                System.out.println(Thread.currentThread().getName() +  "hold lock notify @ "  +
                        new SimpleDateFormat( "HH:mm :ss" ).format(new Date()));
                lock.notifyAll();
                flag =  false ;
                try {                     e.printStackTrace();                 }             }             //lock again             synchronized (lock) {                 System.out.println(Thread.currentThread().getName() +  "hold lock again @ "  +                         new SimpleDateFormat( "HH:mm : SS " ) .format (new new a Date ()));                 the try {                     the Thread.sleep (2000);                 } the catch (InterruptedException E) {                     e.printStackTrace ();                 }             }         }     } } copy the code
                    Thread.sleep(2000);
                } catch (InterruptedException e) {

















Copy the code execution result: waitThread flag is true wait @ 17:33:39 notifyThreadhold lock notify @ 17:33:40 notifyThreadhold lock again @ 17:33:42 waitThreadflag is false running @ 17:33:44 Copy the third line of the code and The output order of the fourth line may be interchanged. The above example illustrates the details that need to be paid attention to when calling wait(), notify(), and notifyAll():

To use wait(), notify() and notifyAll(), you need to lock the calling object first. After calling the wait() method, the thread state changes from RUNNING to WAITING, and the current thread is placed in the waiting queue of the object. After notify() or notifyAll() is called, the waiting thread will still not be released from wait(). After the thread that calls notify() or notifyAll() releases the lock, the waiting thread has the opportunity to release it from wait(). The notify() method moves a waiting thread in the waiting queue from the waiting queue to the synchronization queue, and the notifyAll() method moves all the threads in the waiting queue to the synchronization queue, and the status of the moved thread changes from WAITING to BLOCKED . The premise of returning from the wait() method is to obtain the lock of the calling object.

Illustration of wait and notify:

The classic paradigm of waiting/notifying waiting parties (consumers) abide by the following principles:

Acquire the lock of the object if the condition is not met, then call the wait() method of the object, and still need to check the condition after being notified, and execute the corresponding logic when the condition is met

//Corresponding pseudocode synchronized(object) {while (condition is not satisfied) {object.wait();} corresponding processing logic} Copy the code and notify the party (producer) to comply with the following principles:

Obtain the object's lock change condition to notify all threads waiting on the object

synchronized(object) {change the condition object. notifyAll(); Copy code Pipeline input/output stream The difference between pipeline input/output stream and ordinary file input/output stream or network input/output stream is that it is mainly used for threads Data transmission between the two, and the transmission medium is memory. Pipeline input/output streams include four specific implementations: PipedInputStream, PipedOutputStream, PipedReader, and PipedWriter. The first two are byte-oriented, and the latter two are character-oriented.

public class Piped {
    public static void main(String[] args) throws IOException {
        PipedReader reader = new PipedReader();
        PipedWriter writer = new PipedWriter();

        //Connect the input stream and the output stream, otherwise it will be thrown when using IOException
        reader.connect(writer);

        Thread printThread = new Thread(new Print(reader),  "printThread" );
        printThread.start();
        int receive = 0;

        try {
            while  ((receive = System.in.read( )) != -1) {
                writer.write(receive);
            }
        } finally {
            writer.close();
        }

    } class Print implements Runnable {
}


    private PipedReader reader;
    public Print(PipedReader reader) {
        this.reader = reader;
    }

    @Override
    public void  run () {
        int receive = 0;
        try {
            while  ((receive = reader.read())! -1 =) {
                of System.out.print ((char) the receive);
            }
        } the catch (IOException E) {
            e.printStackTrace ();
        }
    }

copy the code

}


Copy the code to
run the program, enter the string, you can see that the string is output as it is:
Hello World!
Hello World!
Copy code
Thread.join()
If a thread A executes the thread.join() statement, its meaning is that the current Thread A waits for the thread thread to terminate before returning from thread.join(). In addition to the join() method, thread Thread() also provides two methods with timeout characteristics: join(long millis) and join(long millis, int nanos). These two timeout methods indicate that if the thread thread does not terminate within a given timeout period, it will return from the timeout method.
public class TestJoin {
    public static void main(String[] args) {
        Thread one = new Thread(new JoinOne(),  "Thread one" );
        Thread two = new Thread(new JoinTwo(one),  "Thread two" );
        one.start();
        two.start();
    }
}

class JoinOne implements Runnable {

    @Override
    public void run () { (int i = 0; i <100; i++) {
        for  (int i = 0; i <100; i++) {
            System.out.println(Thread.currentThread().getName() +  "---> "  + i);
        }
    }
}

class JoinTwo implements Runnable {
    private Thread thread;
    public JoinTwo(Thread thread) {
        this.thread = thread;
    }

    @Override
    public void  run () {
        try {
            thread.join(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for
            System. out.println(Thread.currentThread().getName() +  "---> "  + i);
        }
    }
}
Copy code

Copy the code and execute the above code, and you will find that the printing of thread two will start after thread one ends. In the source code of Thread.join(), the join() method will call the overloaded method join(long millis), passing in the parameter 0, so Thread.join() and Thread.join(0) are the same. The bottom layer of the join method calls the wait() method

Final void the Join the synchronized public () throws InterruptedException {
 //condition is not satisfied, continue to wait for
 the while  (isAlive ()) {
  the wait (0);
 }
 //condition is met, the method returns
}
copy the code

Author: xs Link: https://juejin.cn/post/6906062070165274638