Java multithreaded programming USES the Synchronized keyword to synchronize class methods

  • 2020-04-01 02:50:09
  • OfStack


public synchronized void run()
{     
}

As you can see from the above code, you can synchronize the run method by adding the synchronized keyword between void and public. That is, for an object instance of the same Java class, the run method can only be called by one thread at a time, and can only be called by another thread after the current run is executed. Even if the current thread executes the yield method in the run method, it only pauses once. Because other threads cannot execute the run method, the current thread will eventually continue execution. Take a look at the following code:
The sychronized keyword is bound to only one instance of the object

class Test
  {
        public synchronized void method()
       {

       }
  }

  public class Sync implements Runnable
  {
       private Test test;
       public void run()
       {
            test.method();
       }
       public Sync(Test test)
       {
           this.test = test;
       }
       public static void main(String[] args) throws Exception
       {
           Test test1 =  new Test();
           Test test2 =  new Test();
           Sync sync1 = new Sync(test1);
           Sync sync2 = new Sync(test2);
           new Thread(sync1).start();
           new Thread(sync2).start(); 
       }
   }
 

Method methods in the Test class are synchronized. But the code above creates two instances of the Test class, so the method methods for test1 and test2 are executed separately. For method to synchronize, you must pass in an instance of the same Test class to its constructor when creating an instance of the Sync class, as shown in the following code:
Sync sync1 = new Sync(test1);
You can use synchronized to synchronize static methods as well as non-static methods. If method can be defined as follows:

class Test 
{
    public static synchronized void method() {   }
}

The object instance to create the Test class is as follows:
Test Test = new Test();
For static methods, as long as the synchronized keyword is added, the method is synchronized, and whether method methods are invoked using test.method() or test.method(), methods are synchronized and there is no problem with multiple instances of non-static methods.
The Singleton pattern in the 23 design patterns is also thread-unsafe if designed the traditional way, and the code below is a thread-unsafe Singleton pattern.


package test;
//Thread-safe Singleton pattern
class Singleton
{
    private static Singleton sample;
    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        if (sample == null)
        {
            Thread.yield(); //To amplify the Singleton pattern, threads are not safe
            sample = new Singleton();
        }
        return sample;
    }
}
public class MyThread extends Thread
{
    public void run()
    {
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton.hashCode());
    }
    public static void main(String[] args)
    {
        Thread threads[] = new Thread[5];
        for (int i = 0; i < threads.length; i++)
            threads[i] = new MyThread();
        for (int i = 0; i < threads.length; i++)
            threads[i].start();
    }
}

The yield method is called in the above code to make the single-piece pattern thread unsafe, and if you remove this line, the above implementation is still thread-unsafe, but much less likely to occur.
The results of the program are as follows:

25358555
26399554
7051261
29855319
5383406

The results of the above run may have all the same in different running environments, but generally the output of these five lines will not be identical. As you can see from this output, the number of object instances obtained by the getInstance method is five, not the one we expected. This is because when a Thread executes thread.yield (), it hands over CPU resources to another Thread. Because did not perform when switching between threads to create instances of Singleton object statement, as a result, these a few threads are passed the if judgment, therefore, can produce the build five object instance is (may be four or three objects created instance, depending on how many threads before creating the Singleton object passed if judgment, every run may results will be different).
To make the singleton pattern above thread-safe, just add the synchronized keyword to getInstance. The code is as follows:
Public static synchronized Singleton getInstance() {    }
Of course, there is an easier way to set up a Singleton object when defining a Singleton variable. The code is as follows:
Private static final Singleton sample = new Singleton();
Then simply return the sample in the getInstance method. This approach, while simple, is not as flexible as creating a Singleton object in the getInstance method. The reader may choose to implement the singleton pattern in different ways according to specific requirements.

There are four points to note when using the synchronized keyword:

1.   The synchronized keyword cannot be inherited.
Although synchronized can be used to define methods, it is not part of the method definition, and therefore the synchronized keyword cannot be inherited. If a method in a parent class USES the synchronized keyword and the method is overridden in a subclass, the method in the subclass is not synchronized by default, and you must explicitly add the synchronized keyword to the method in the subclass. Of course, you can also call the corresponding method in the parent class from a subclass method, so that even though the methods in the subclass are not synchronized, the subclass calls the parent class's synchronized method, so the subclass's methods are synchronized. The example code for these two approaches is as follows:
Adds the synchronized keyword to a subclass method


class Parent
{
    public synchronized void method() {   }
}
class Child extends Parent
{
    public synchronized void method() {   }
}

Calls the parent class's synchronous method in a subclass method


class Parent
{
    public synchronized void method() {   }
}
class Child extends Parent
{
    public void method() { super.method();   }
}

2.   The synchronized keyword cannot be used when defining interface methods.
3.   Constructors cannot use the synchronized keyword, but they can use the synchronized block discussed in the next section.
4.   Synchronized is freely available.
In the previous examples, the synchronized keyword was placed before the method's return type. But this is not the only place that synchronized can be placed. In non-static methods, synchronized can also be placed first in the method definition. In static methods, synchronized can be placed first in the static method. The code is as follows:


public synchronized void method();
synchronized public void method();
public static synchronized void method();
public synchronized static void method();
synchronized public static void method();

Note, however, that synchronized cannot be placed after a method return type, and the following code is incorrect:


public void synchronized method();
public static void synchronized method();

The synchronized keyword can only be used to synchronize methods, not class variables, and the following code is also incorrect.


public synchronized int n = 0;
public static synchronized int n = 0;

Although the use of the synchronized keyword is the safest method of synchronization, the heavy use of the synchronized keyword causes unnecessary resource consumption and performance loss. Although synchronized locking appears to be a method, it is actually a class that is synchronized locked. That is, if both the non-static methods method1 and method2 are defined using synchronized, method2 cannot be executed until method1 is completed. The case is similar for static and non-static methods. But static and non-static methods do not interact. Take a look at the following code:


package test;
public class MyThread1 extends Thread
{
    public String methodName;
    public static void method(String s)
    {
        System.out.println(s);
        while (true)

    }
    public synchronized void method1()
    {
        method(" The static method1 methods ");
    }
    public synchronized void method2()
    {
        method(" The static method2 methods ");
    }
    public static synchronized void method3()
    {
        method(" static method3 methods ");
    }
    public static synchronized void method4()
    {
        method(" static method4 methods ");
    }
    public void run()
    {
        try
        {
            getClass().getMethod(methodName).invoke(this);
        }
        catch (Exception e)
        {
        }
    }
    public static void main(String[] args) throws Exception
    {
        MyThread1 myThread1 = new MyThread1();
        for (int i = 1; i <= 4; i++)
        {
            myThread1.methodName = "method" + String.valueOf(i);
            new Thread(myThread1).start();
            sleep(100);
        }
    }
}

The operation results are as follows:


 The static method1 methods 
 static method3 methods 

As you can see from the results of the run above, method2 and method4 cannot be run until method1 and method3 are finished. Therefore, we can conclude that using the synchronized keyword to define a non-static method in a class will affect all non-static methods defined using the synchronized keyword in this class. If a static method is defined, it affects all static methods defined in the class using the synchronized keyword. This is a bit like a table lock in a data table. When a record is modified, the system locks the entire table.


Related articles: