首页  >  文章  >  Java  >  Java 中的同步是什么?

Java 中的同步是什么?

WBOY
WBOY原创
2024-08-30 16:18:111205浏览

Java 中的同步是一种 Java 功能,它限制多个线程同时尝试访问公共共享资源。这里的共享资源是指外部文件内容、类变量或数据库记录。

开始您的免费软件开发课程

网络开发、编程语言、软件测试及其他

同步在多线程编程中被广泛使用。 “Synchronized”这个关键字使您的代码能够仅允许单个线程对其进行操作,而在此期间不会受到任何其他线程的干扰。

为什么我们需要 Java 中的同步?

  • Java 是一种多线程编程语言。这意味着两个或多个线程可以同时运行以完成任务。当线程同时运行时,很有可能出现您的代码可能提供意外结果的情况。
  • 你可能想知道,如果多线程会导致错误的输出,那么为什么它被认为是 Java 中的一个重要特性?
  • 多线程通过并行运行多个线程使您的代码更快,减少代码执行时间并提供高性能。然而,由于通常称为竞争条件的情况,使用多线程环境会导致输出不准确。

什么是竞争条件?

当两个或多个线程并行运行时,它们倾向于在该时间点访问和修改共享资源。线程调度算法决定线程执行的顺序。

因此,由于线程调度程序单独控制线程,因此无法预测线程的执行顺序。这会影响代码的输出并导致输出不一致。由于多个线程相互竞争来完成操作,因此该条件称为“竞争条件”。

例如,让我们考虑以下代码:

class Modify:
package JavaConcepts;
public class Modify implements Runnable{
private int myVar=0;
public int getMyVar() {
return myVar;
}
public void setMyVar(int myVar) {
this.myVar = myVar;
}
public void increment() {
myVar++;
}
@Override
public void run() {
// TODO Auto-generated method stub
this.increment();
System.out.println("Current thread being executed "+ Thread.currentThread().getName() + "Current Thread value " + this.getMyVar());
}
}
class RaceCondition:
package JavaConcepts;
public class RaceCondition {
public static void main(String[] args) {
Modify mObj = new Modify();
Thread t1 = new Thread(mObj, "thread 1");
Thread t2 = new Thread(mObj, "thread 2");
Thread t3 = new Thread(mObj, "thread 3");
t1.start();
t2.start();
t3.start();
}
}

连续运行上述代码,输出将如下:

我们的输入1:

当前正在执行的线程 线程1 当前线程值3

当前正在执行的线程 线程3 当前线程值2

当前正在执行的线程 线程2 当前线程值3

输出2:

当前正在执行的线程 thread 3 Current Thread value 3

当前正在执行的线程 线程2 当前线程值3

当前正在执行的线程 线程1 当前线程值3

输出3:

当前正在执行的线程 线程2 当前线程值3

当前正在执行的线程 线程1 当前线程值3

当前正在执行的线程 thread 3 Current Thread value 3

输出4:

当前正在执行的线程 线程1 当前线程值2

当前正在执行的线程 thread 3 Current Thread value 3

当前正在执行的线程 thread 2 Current Thread value 2

Java 中的同步是什么?

  • 从上面的示例中,您可以得出结论,线程是随机执行的,而且该值不正确。按照我们的逻辑,该值应该增加 1。但是,这里大多数情况下输出值为 3,少数情况下为 2。
  • 这里的“myVar”变量是多个线程正在执行的共享资源。线程同时访问和修改“myVar”的值。让我们看看如果我们注释掉其他两个线程会发生什么。

Java 中的同步是什么?

本例的输出为:

当前正在执行的线程thread 1 Current Thread value 1

这意味着当单个线程运行时,输出是预期的。但是,当多个线程运行时,每个线程都会修改该值。因此,需要将处理共享资源的线程数量限制为一次一个线程。这是通过使用同步来实现的。

Understanding What is Synchronization in Java

  • Synchronization in Java is achieved with the help of the keyword “synchronized”. This keyword can be used for methods or blocks, or objects but cannot be used with classes and variables. A synchronized piece of code allows only one thread to access and modify it at a given time.
  • However, a synchronized piece of code affects code performance as it increases the waiting time of other threads trying to access it. So a piece of code should be synchronized only when there is a chance for a race condition to occur. If not, one should avoid it.

How does Synchronization in Java work internally?

  • Internally synchronization in Java has been implemented with the help of the lock (also known as a monitor) concept. Every Java object has its own lock. In a synchronized block of code, a thread needs to acquire the lock before being able to execute that particular block of code. Once a thread acquires the lock, it can execute that piece of code.
  • On completion of execution, it automatically releases the lock. If another thread requires to operate on the synchronized code, it waits for the current thread operating on it to release the lock. This process of acquiring and releasing locks is internally taken care of by the Java virtual machine. A program is not responsible for acquiring and release of locks by the thread. The remaining threads can, however, execute any other non-synchronized piece of code simultaneously.

Let us synchronize our previous example by synchronizing the code inside the run method using the synchronized block in class “Modify” as below:

class Modify:
package JavaConcepts;
public class Modify implements Runnable{
private int myVar=0;
public int getMyVar() {
return myVar;
}
public void setMyVar(int myVar) {
this.myVar = myVar;
}
public void increment() {
myVar++;
}
@Override
public void run() {
// TODO Auto-generated method stub
synchronized(this) {
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
}
}
}

The code for the class “RaceCondition” remains the same. Now on running the code, the output is as follows:

Output1:

The current thread being executed thread 1 Current Thread value 1

The current thread being executed thread 2 Current Thread value 2

The current thread being executed thread 3 Current Thread value 3

Output2:

The current thread being executed thread 1 Current Thread value 1

The current thread being executed thread 3 Current Thread value 2

The current thread being executed thread 2 Current Thread value 3

Java 中的同步是什么?

Notice that our code is providing the expected output. Here every thread is incrementing the value by 1 for the variable “myVar” (in class “Modify”).

Note: Synchronization is required when multiple threads are operating on the same object. If multiple threads are operating on multiple objects, then synchronization is not required.

For Example, let us modify the code in the class “RaceCondition” as below and work with the previously unsynchronized class “Modify”.

package JavaConcepts;
public class RaceCondition {
public static void main(String[] args) {
Modify mObj = new Modify();
Modify mObj1 = new Modify();
Modify mObj2 = new Modify();
Thread t1 = new Thread(mObj, "thread 1");
Thread t2 = new Thread(mObj1, "thread 2");
Thread t3 = new Thread(mObj2, "thread 3");
t1.start();
t2.start();
t3.start();
}
}

Output:

The current thread being executed thread 1 Current Thread value 1

The current thread being executed thread 2 Current Thread value 1

The current thread being executed thread 3 Current Thread value 1

Java 中的同步是什么?

Types of  Synchronization in Java

There are two types of thread synchronization, one being mutually exclusive and the other inter-thread communication.

1. Mutually Exclusive

  • In this case, threads obtain the lock before operating on an object, thereby avoiding working with objects that have had their values manipulated by other threads.
  • This can be achieved in three ways:
i. Synchronized Method

We can make use of the “synchronized” keyword for a method, thus making it a synchronized method. Every thread that invokes the synchronized method will obtain the lock for that object and release it once its operation is completed. In the above example, we can make our “run()” method as synchronized by using the “synchronized” keyword after the access modifier.

@Override
public synchronized void run() {
// TODO Auto-generated method stub
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
}

The output for this case will be:

The current thread being executed thread 1 Current Thread value 1

The current thread being executed thread 3 Current Thread value 2

The current thread being executed thread 2 Current Thread value 3

ii. Static synchronized method

In order to synchronize static methods, one needs to acquire its class level lock. After a thread obtains the class level lock, only then it will be able to execute a static method. While a thread holds the class level lock, no other thread can execute any other static synchronized method of that class. However, the other threads can execute any other regular method or regular static method or even non-static synchronized method of that class.

For example, let us consider our “Modify” class and make changes to it by converting our “increment” method to a static synchronized method. The code changes are as below:

package JavaConcepts;
public class Modify implements Runnable{
private static int myVar=0;
public int getMyVar() {
return myVar;
}
public void setMyVar(int myVar) {
this.myVar = myVar;
}
public static synchronized void increment() {
myVar++;
System.out.println("Current thread being executed " + Thread.currentThread().getName() + " Current Thread value " + myVar);
}
@Override
public void run() {
// TODO Auto-generated method stub
increment();
}
}
iii. Synchronized block

One of the main disadvantages of the synchronized method is that it increases threads waiting time, impacting the performance of the code. Therefore, to synchronize only the required lines of code in place of the entire method, one needs to make use of a synchronized block. Using synchronized block reduces the waiting time of the threads and improves performance as well. In the previous example, we have already made use of synchronized block while synchronizing our code for the first time.

Example:

public void run() {
// TODO Auto-generated method stub
synchronized(this) {
this.increment();
System.out.println("Current thread being executed "
+ Thread.currentThread().getName() + " Current Thread value " + this.getMyVar());
}
}

2. Thread Co-ordination

For synchronized threads, inter-thread communication is an important task. Inbuilt methods that help achieve inter-thread communication for synchronized code are namely:

  • wait()
  • notify()
  • notifyAll()
Note: These methods belong to the object class and not the thread class. For a thread to be able to invoke these methods on an object, it should be holding the lock on that object. Also, these methods cause a thread to release its lock on the object on which it is being invoked.
i. wait()

A thread on invoking the wait() method releases the lock on the object and goes into a waiting state. It has two method overloads:

  • public final void wait()throws InterruptedException
  • public final void wait(long timeout)throws InterruptedException
  • public final void wait(long timeout, int Nanos) throws InterruptedException
ii. notify()

A thread sends a signal to another thread in the waiting state by making use of the notify() method. It sends the notification to only one thread such that this thread can resume its execution. Which thread will receive the notification among all the threads in the waiting state depends on the Java Virtual Machine.

public final void notify()
iii. notifyAll()

When a thread invokes the notifyAll() method, every thread in its waiting state is notified. These threads will be executed one after the other based on the order decided by the Java Virtual Machine.

public final void notifyAll()

Conclusion

In this article, we have seen how working in a multi-threaded environment can lead to data inconsistency due to a race condition, how synchronization helps us overcome this by limiting a single thread to operate on a shared resource at a time. Also, how synchronized threads communicate with each other.

以上是Java 中的同步是什么?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
上一篇:Avro File下一篇:Concurrency in Java