This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.

In the previous section, we showed you how to create threads using methods that inherit from the Thread class. However, there is an implicit restriction in Java, which has a single-inheritance restriction that prevents Thread from inheriting from other classes. So in general, it is recommended to create multithreading by implementing interfaces. The Thread class inherits the Runnable interface itself, and the run method we need to override comes from the Runnable interface. The Thread class also provides a constructor that takes a class that implements the Runnable interface. Given these conditions, the new way to create threads is obvious, and we’ll modify the demo at the end of the previous section a bit:

// Class threadTest implements Runnable{String name; threadTest(String name){ this.name=name; } @Override public void run() { for(int i=0; i<500; ++i){ } System.out.println(name+" finished!" ); }} public class LearnThread {public static void main(String[] args) {threadTest t1=new threadTest(" thread1 "); ThreadTest t2=new threadTest(" thread2 "); ThreadTest t3=new threadTest(" thread3 "); New Thread(t1).start(); new Thread(t1).start(); new Thread(t2).start(); new Thread(t3).start(); }}Copy the code

You can compare this to the code at the end of the previous section, and you’ll get a good idea of what these two ways of creating threads have in common. If we have A class A that implements the Runnable interface and can pass it into the Thread class to start A new Thread, can we pass it into the Thread class to start several threads? The answer is yes. The Thread constructor allows you to pass in A class that implements the Runnable interface with A string indicating the name of the Thread, regardless of whether the class (such as A) is being used by other threads. Modify the above code slightly as follows:

class threadTest implements Runnable{ private static int i=50; @ Override public void the run () {while (I > 0) {/ / the Thread here. CurrentThread. GetName method can get the name of the Thread is executing System.out.println(thread.currentThread ().getName()+" getName "+ I); i--; } } } public class LearnThread { public static void main(String[] args) { threadTest t1=new threadTest(); New Thread(t1," Thread 1").start(); // We started three threads for T1 at the same time! New Thread(t1," Thread 2").start(); New Thread(t1," Thread 3").start(); }}Copy the code

If you look at my results (part), you’ll see something unexpected

Thread 1 got 50 threads, thread 3 got 50 threads, thread 3 got 48 threads, thread 3 got 47 threads, thread 3 got 46 threads, thread 3 got 45 threads, thread 3 got 44 threads, thread 3 got 43 threads, thread 2 got 50 threads, thread 3 got 42 threads, thread 1 got 49Copy the code

As you can see, 50 is picked up by three threads, but in our run method, we should subtract 1 every time I is picked up, which is a really strange situation. This is actually called the concurrency problem, and I’ll explain it in detail below. Thread synchronization is required when multiple threads access the same object and some of them attempt to modify the object. The condition for thread synchronization is queue + lock. These two concepts are also widely used in real life. Imagine you’re at an ATM, people are standing in line at an ATM, you join the line, and when it’s your turn, you can go into the small room, lock the door, and safely proceed with your withdrawal. When you’re done, open the door so the latter person can come in and take care of his business. Threads in computers do not understand etiquette, and they do not queue spontaneously. But we can lock the shared object they all want, and only after the current thread has finished using the object (all the other threads are waiting in the blocking queue) can another thread be allowed to manipulate the shared object (which thread wins? There is also the issue of contention between threads. If there is no lock (door to the ATM cubicle), the queue of threads will try to crowd into the cubicle together, as shown in the demo above. All three threads squeezed into the small room at about the same time and all got the number 50 (because none of the threads had had time to change I to 49). Next, I’ll introduce a common method of locking in Java, using the synchronized keyword, which can be used in two ways. 1. Add synchronized to a method modifier, which locks this, the object on which the method resides. Let’s take a look at this demo

public class LearnThread implements Runnable { private static int count=0; @Override public synchronized void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " get " + (count++)); } } public static void main(String[] args) { LearnThread t1 = new LearnThread(); New Thread(t1, "Thread 1").start(); New Thread(t1, "Thread 2").start(); }}Copy the code

We added the synchronized keyword to the Run method of the LearnThread class, and the class is now locked (with a small room to keep it locked). Our three threads can only honestly enter the room one by one to manipulate the locked object. Here is the program output:

Thread 1 get 0 thread 1 GET 1 thread 1 GET 2 threads 1 GET 3 threads 1 GET 4 threads 2 GET 5 threads 2 GET 6 threads 2 GET 7 threads 2 get 8 threads 2 get 9Copy the code

Thread 1 takes the lock first, and when it completes its task, the lock is handed over to thread 2. Without the synchronized keyword, the result would be confusing, so try it out to impress.

You can run this code to see the difference between a schronized code block and other threads that block only when they access it

public class LearnThread implements Runnable { private static int count=0; private static int count2=0; @Override public void run() { for (int i = 0; i < 5; I++) {system.out.println (thread.currentthread ().getname () + "non-blocking" + (count2++)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }} synchronized (this) {for (int I = 0; i < 5; I++) {system.out.println (thread.currentthread ().getname () + "blocking" + (count++)); } } } public static void main(String[] args) { LearnThread t1 = new LearnThread(); New Thread(t1, "Thread 1").start(); New Thread(t1, "Thread 2").start(); }}Copy the code

My run results are as follows

Thread 2 non-blocking 1 thread 1 non-blocking 0 thread 1 non-blocking 2 threads 2 non-blocking 3 threads 1 non-blocking 4 threads 2 non-blocking 5 threads 1 non-blocking 6 threads 2 non-blocking 7 threads 2 non-blocking 8 threads 1 non-blocking 9 threads 2 blocking 0 Thread 2 blocked 1 thread 2 blocked 2 threads 2 blocked 3 threads 2 blocked 4 threads 1 blocked 5 threads 1 blocked 6 threads 1 blocked 7 threads 1 blocked 8 threads 1 blocked 9Copy the code

As you can see, access to the unsyncronized code block is chaotic because two threads can access this part at the same time. Threads that are blocked must be completed one by one.