Create two threads and observe the errors in Concurrency:
package test; public class TestThread { public static void main(String[] args) { Init(); } public static void Init() { //Create first thread new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub System.out.println("yanghao"); } } }).start(); //Create a second thread new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub System.out.println("dingyan"); } } }).start(); } }
Run by test on:
It can be seen that the direct printing string cannot be seen, and there are errors in concurrency. Therefore, print according to characters
The code is as follows:
package test; public class TestThread { public static void main(String[] args) { Init(); } public static void Init() { //Create first thread new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub //System.out.println("yanghao"); Outer("yanghao"); } } }).start(); //Create a second thread new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub //System.out.println("dingyan"); Outer("dingyan"); } } }).start(); } public static void Outer(String str){ int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } } }
The test was as follows:
At this point, the problem arises: when two threads are running at the same time, the output is abnormal and messy
To solve this problem, we need to use the synchronized keyword. Let's try:
ackage test; public class TestThread { public static void main(String[] args) { Init(); } public static void Init() { //Create first thread new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub //System.out.println("yanghao"); Outer1("yanghao"); } } }).start(); //Create a second thread new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub //System.out.println("dingyan"); Outer2("dingyan"); } } }).start(); } public static synchronized void Outer1(String str){ int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } } public static synchronized void Outer2(String str){ int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } } }
At this point, the test will find that it is back to normal:
In daily work, the most used, safest, and ideal thread delay is to use the thread pool technology ScheduledExecutorService
The implementation is similar, as follows:
package test; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TestThread { public static void main(String[] args) { Init(); } public static void Init() { ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //Create first thread pool.scheduleAtFixedRate(new Runnable() { @Override public void run() { Outer1("yanghao"); } }, 0, 2, TimeUnit.SECONDS); //Create a second thread pool.scheduleAtFixedRate(new Runnable() { @Override public void run() { Outer2("yanghao"); } }, 0, 2, TimeUnit.SECONDS); } public static synchronized void Outer1(String str){ int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } } public static synchronized void Outer2(String str){ int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } } }
Test results:
The synchronized keyword is used up, so what is the synchronization lock?
Look at the code:
package test; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TestThread { public static void main(String[] args) { Init(); } public static void Init() { ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //Create first thread pool.scheduleAtFixedRate(new Runnable() { @Override public void run() { Outer1("yanghao"); } }, 0, 2, TimeUnit.SECONDS); //Create a second thread pool.scheduleAtFixedRate(new Runnable() { @Override public void run() { Outer2("dingyan"); } }, 0, 2, TimeUnit.SECONDS); } private static String token = ""; public static synchronized void Outer1(String str){ synchronized (token) { //Define a lock int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } System.out.println(""); } } public static synchronized void Outer2(String str){ synchronized (token) { //Define a lock int length = str.length(); for (int i=0; i<length; i++){ System.out.print(str.charAt(i)); } System.out.println(""); } } }
The test shows that synchronization is also achieved:
Synchronization lock is to create a synchronization block at the place of execution and put the code to be executed into it to ensure that when calling the code, it can run independently without interference.
So what's a token?
It's just a lock
The lock for a synchronized code block is arbitrary. As long as different threads execute the same synchronization code block, this lock is set at will.