Three ways to create a thread
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 the 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 the code
Avoid single inheritance limitations, flexible and convenient, easy to use the same object by multiple threads using anonymous inner class simplify 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
// Create threads using anonymous inner classes
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("abc");
}
}).start(); // abc
}
Copy the code
Copying code simplifies code using lambda expressions: any interface that contains only one abstract method is a functional interface. For functional interfaces, we can create objects for that interface through lambda expressions.
interface Test {
void fun();
}
public class LambdaTest {
public static void main(String[] args) {
// lambda expressions
// The contents of the braces are equivalent to overriding the methods in the interface. If the code is only one line, you can remove the 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 code 3. Implement 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 the execution service
ExecutorService ser = Executors.newFixedThreadPool(3);
// Commit 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 the code
Priority in Java threads is controlled by an integer member variable priority, which ranges from 1 to 10. The default priority is 5. The priority can be set by setPriority(int). Threads with a higher priority allocate more time slices than threads with a lower priority. However, thread priority cannot be used as a dependency on program correctness. Six states of Java threads
NEW: the initial state in which the thread is built, but the start() method has not yet been called RUNNABLE: the running state. The Java thread defines the two states of the operating system as “running” and “BLOCKED”, indicating that the thread is BLOCKED at lock WAITING: TIME_WAITING: a state of wait TERMINATED when the current thread is WAITING for some specific action (notification or interruption) from another thread. This state is different from WAITING and can be TERMINATED at a specified time: Terminated status: indicates that the current thread has finished executing
The blocking state is the state in which a thread blocks when it enters a method or code block modified by the synchronized keyword (obtaining the Lock), whereas threads blocking the Lock interface in the Java.concurrent package are in the wait state. Because the Lock interface in the Java.Concurrent package uses the related methods in the LockSupport class for blocking implementations. A Daemon is a support thread because it is used for background scheduling and support work. This means that a Java virtual machine will exit when there are no non-Daemon threads in the machine. So when building Daemon threads, you can’t rely on the contents of the finally block to ensure that the logic to close or clean up resources is performed, because the contents of the finally block are not necessarily executed. The thread can be set to a Daemon thread by calling setDaemonn(true) (the default is false).
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'm the daemon thread");
}
}
}
Copy the code
Copy the code and execute the above code to find no print. Interrupts a thread automatically after it finishes executing, or prematurely if an exception occurs during execution. InterruptedException is thrown to terminate a thread prematurely by calling interrupt() on the thread if it is blocked, waiting, or timed out. However, I/O and synchronized lock blocking cannot be interrupted. A thread checks for interruption by using isInterrupted(). If the thread has been interrupted, this method returns false even if it has been interrupted.
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 to allow sleepThreads and busyThreads to run fully
Thread.sleep(5000);
sleepThread.interrupt();
busyThread.interrupt();
System.out.println("sleepThread interrupted is " + sleepThread.isInterrupted()); // false
System.out.println("busyThread interrupted is " + busyThread.isInterrupted()); // true
// Prevent sleepThreads and busythreads from exiting immediately
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() {
while (true) {
}
}
}
Copy the code
Copy the code to run results: sleepThread interrupted is false busyThread interrupted is true on Java. Lang. InterruptedException: If the sleep Interrupted sleepThread is in the timeout waiting state, an exception is thrown and the thread is terminated prematurely. In this case, the value is false. Wait/notification mechanism One thread changes the value of an object, and another thread senses the change and acts accordingly. The whole process starts in one thread and ends in another thread. The former is the producer, while the latter is the consumer. This pattern separates the “what” and “how”, achieves decoupling at the functional level and scales well architecturally. Java implements similar functionality through a wait/notification mechanism. The wait/notification related methods are available to any Java Object, because they are defined on the superclass java.lang.object of all objects, with the following methods:
NotifyAll () : notifies all threads waiting on an object to wait() : notify() : notifies a thread waiting on an object to return from wait() if the thread has obtained the lock of the object. The thread that called wait() is in a WAITING state and will only return WAITING for notification or interruption from another thread. Note that after calling wait(), the lock of the object is released. Wait (long) : wait for more than a certain amount of time (n milliseconds) and return if no notification is given. Wait (long, int) : For more granular control of the timeout, up to nanoseconds.
The wait/notification mechanism refers to that thread A calls the wait() method of object O to enter the wait state, and another thread B calls the notify() or notifyAll() method of object O. After receiving the notification, thread A returns from the wait() method of object O and 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) {
// If the condition is not met, continuewaitWhile releasing the lock
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();
}
}
// If the conditions are met, 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) {
// Obtain the lock of the lock, and notify. The notification will not release the lock
System.out.println(Thread.currentThread().getName() + "hold lock notify @ " +
new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notifyAll();
flag = false;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Lock again
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + "hold lock again @ " +
new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Copy the code
Copy code execution results: 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 The output order of the third and fourth lines of copy code may be reversed. The above examples illustrate the details of calling wait(), notify(), and notifyAll() :
Using wait(), notify(), and notifyAll() requires locking the calling object first. After calling wait(), the thread state changes from RUNNING to WAITING and the current thread is placed on the object’s wait queue. After notify() or notifyAll() is called, the waiting thread does not release the lock from wait() until the thread that calls notify() or notifyAll() releases the lock. The notify() method moves one thread in the wait queue from the wait queue to the synchronization queue, and notifyAll() method moves all threads in the wait queue to the synchronization queue, and the status of the moved thread changes from WAITING to BLOCKED. The return from wait() is conditional upon obtaining the lock of the calling object.
Wait and notify
The classic paradigm of wait/notification waits (consumers) adhere to the following principles:
If the condition is not met, the object’s wait() method is called, and the logic is executed if the condition is still checked
Synchronized (object) {while(condition not satisfied) {object.wait (); } The notification party (producer) of the copied code follows the following principles:
Obtain the lock change condition of the object to notify all threads waiting on the object
Synchronized (object) {change the condition object. NotifyAll (); Copy code pipe I/O stream Pipe I/o stream is different from normal file I/o stream or network I/o stream in that it is mainly used for data transfer between threads, and the transfer medium is memory. There are four specific implementations of piped input/output streams: PipedInputStream, PipedOutputStream, PipedReader, and PipedWriter. The first two are byte oriented and the last 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 and output streams, otherwise IOException will be thrown when used
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) {
System.out.print((char) receive);
}
} catch (IOException e) {
e.printStackTrace();
}
}
Copy the code
}
Copy the code
Run the program, enter a string, and see the string printed as it is:
Hello World!
Hello World!
Copy the code
The use of the Thread. The join ()
If thread A executes thread.join(), it means that thread A is waiting for thread A to terminate before returning from Thread.join (). Thread() provides join() as well as join(long millis) and JOIN (Long millis, int nanos). These two timeout methods indicate that a thread will be returned from the timeout method if it does not terminate within a given timeout period.
public class TestJoin {
public static void main(String[] args) {
Thread one = new Thread(new JoinOne(), "One thread");
Thread two = new Thread(new JoinTwo(one), "Two" thread);
one.start();
two.start();
}
}
class JoinOne implements Runnable {
@Override
public void run() {
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 (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "- >" + i);
}
}
}
Copy the code
Copy the code and execute the above code to find that the printing of thread two begins after thread one finishes. In the source code of Thread.join(), the join() method calls the overloaded join(long millis), passing in 0, so thread.join () and Thread.join(0) are the same. The underlying join method calls the wait() method
public final synchronized void join() throws InterruptedException {
// If the condition is not met, wait
while (isAlive()) {
wait(0);
}
// If the condition is met, the method returns
}
Copy the code
Author: xs link: https://juejin.cn/post/6906062070165274638