“同步”是什么意思? 意思是?

发布于 2024-07-25 18:22:58 字数 172 浏览 9 评论 0原文

我对 synchronized 关键字的用法和意义有一些疑问。

  • synchronized 关键字有何意义?
  • 方法何时应该同步
  • 从程序上和逻辑上来说这意味着什么?

I have some questions regarding the usage and significance of the synchronized keyword.

  • What is the significance of the synchronized keyword?
  • When should methods be synchronized?
  • What does it mean programmatically and logically?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

少钕鈤記 2024-08-01 18:22:58

synchronized 关键字是关于不同的线程读取和写入相同的变量、对象和资源。 这在 Java 中不是一个简单的话题,但这里引用了 Sun 的一句话:

同步方法可以实现简单的
防止线程的策略
干扰和记忆一致性
错误:如果对象可见
多个线程,所有读取或
写入该对象的变量是
通过同步方法完成。

简而言之:当您有两个线程正在读取和写入同一“资源”(例如名为 foo 的变量)时,您需要确保这些线程以原子方式访问变量。 如果没有 synchronized 关键字,线程 1 可能看不到线程 2 对 foo 所做的更改,或者更糟糕的是,它可能只更改了一半。 这不是你逻辑上所期望的。

再说一次,这在 Java 中是一个不平凡的话题。 要了解更多信息,请探索 SO 和 Interwebs 上的主题:

继续探索这些主题,直到名称​​“Brian Goetz” 在你的大脑中永久地与术语“并发”联系在一起。

The synchronized keyword is all about different threads reading and writing to the same variables, objects and resources. This is not a trivial topic in Java, but here is a quote from Sun:

synchronized methods enable a simple
strategy for preventing thread
interference and memory consistency
errors: if an object is visible to
more than one thread, all reads or
writes to that object's variables are
done through synchronized methods.

In a very, very small nutshell: When you have two threads that are reading and writing to the same 'resource', say a variable named foo, you need to ensure that these threads access the variable in an atomic way. Without the synchronized keyword, your thread 1 may not see the change thread 2 made to foo, or worse, it may only be half changed. This would not be what you logically expect.

Again, this is a non-trivial topic in Java. To learn more, explore topics here on SO and the Interwebs about:

Keep exploring these topics until the name "Brian Goetz" becomes permanently associated with the term "concurrency" in your brain.

固执像三岁 2024-08-01 18:22:58

好吧,我认为我们已经有了足够的理论解释,所以考虑一下这段代码。

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;

    public TestThread(String name, TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }

    @Override
    public void run() {
        theDemo.test(name);
    }

    public static class TheDemo {
        public synchronized void test(String name) {
            for (int i = 0; i < 10; i++) {
                System.out.println(name + " :: " + i);
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1", theDemo);
        new TestThread("THREAD 2", theDemo);
        new TestThread("THREAD 3", theDemo);
    }
}
   

注意:只要前一个线程的执行尚未完成,synchronized 就会阻止下一个线程对方法 test() 的调用。 线程一次只能访问此方法。 如果没有synchronized,所有线程都可以同时访问此方法。

当线程调用对象的同步方法“test”时(这里对象是“TheDemo”类的实例),它会获取该对象的锁,任何新线程都不能调用同一对象的任何同步方法,只要前一个线程获得锁的对象不会释放锁。

当调用类的任何静态同步方法时,都会发生类似的情况。 线程获取与该类关联的锁(在这种情况下,该类实例的任何非静态同步方法都可以由任何线程调用,因为该对象级锁仍然可用)。 只要当前持有锁的线程未释放类级别锁,任何其他线程都将无法调用该类的任何静态同步方法。

同步输出

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

不同步输出

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9

Well, I think we had enough of theoretical explanations, so consider this code

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;

    public TestThread(String name, TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }

    @Override
    public void run() {
        theDemo.test(name);
    }

    public static class TheDemo {
        public synchronized void test(String name) {
            for (int i = 0; i < 10; i++) {
                System.out.println(name + " :: " + i);
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1", theDemo);
        new TestThread("THREAD 2", theDemo);
        new TestThread("THREAD 3", theDemo);
    }
}
   

Note: synchronized blocks the next thread's call to method test() as long as the previous thread's execution is not finished. Threads can access this method one at a time. Without synchronized all threads can access this method simultaneously.

When a thread calls the synchronized method 'test' of the object (here object is an instance of 'TheDemo' class) it acquires the lock of that object, any new thread cannot call ANY synchronized method of the same object as long as previous thread which had acquired the lock does not release the lock.

Similar thing happens when any static synchronized method of the class is called. The thread acquires the lock associated with the class(in this case any non static synchronized method of an instance of that class can be called by any thread because that object level lock is still available). Any other thread will not be able to call any static synchronized method of the class as long as the class level lock is not released by the thread which currently holds the lock.

Output with synchronised

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

Output without synchronized

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9
戏舞 2024-08-01 18:22:58

synchronized 关键字可防止多个线程同时访问代码块或对象。 Hashtable 的所有方法都是同步的,因此一次只有一个线程可以执行其中任何一个方法。

当使用非同步构造(例如HashMap)时,您必须在代码中构建线程安全功能以防止一致性错误。

The synchronized keyword prevents concurrent access to a block of code or object by multiple threads. All the methods of Hashtable are synchronized, so only one thread can execute any of them at a time.

When using non-synchronized constructs like HashMap, you must build thread-safety features in your code to prevent consistency errors.

笙痞 2024-08-01 18:22:58

synchronized 表示在多线程环境中,具有 synchronized 方法/块的对象不允许两个线程访问 synchronized代码> 同时代码的方法/块。 这意味着一个线程在另一个线程更新它时无法读取它。

第二个线程将等待,直到第一个线程完成其执行。 开销是速度,但优点是保证数据的一致性。

如果您的应用程序是单线程的,则synchronized 块不会提供任何好处。

synchronized means that in a multi threaded environment, an object having synchronized method(s)/block(s) does not let two threads to access the synchronized method(s)/block(s) of code at the same time. This means that one thread can't read while another thread updates it.

The second thread will instead wait until the first thread completes its execution. The overhead is speed, but the advantage is guaranteed consistency of data.

If your application is single threaded though, synchronized blocks does not provide benefits.

季末如歌 2024-08-01 18:22:58

synchronized 关键字使线程在进入方法时获得锁,这样同一时间只有一个线程可以执行该方法(对于给定的对象实例,除非是静态方法)。

这通常被称为使类线程安全,但我想说这是一种委婉的说法。 虽然同步确实可以保护 Vector 的内部状态不被损坏,但这通常对 Vector 的用户没有多大帮助。

考虑一下:

 if (vector.isEmpty()){
     vector.add(data);
 }

尽管所涉及的方法是同步的,但由于它们是单独锁定和解锁的,两个不幸的定时线程可以创建一个具有两个元素的向量。

因此,实际上,您还必须在应用程序代码中进行同步。

因为方法级同步 a) 当您不需要同步时成本高昂,b) 当您需要同步时不足,因此现在有非同步的替代方案(在 Vector 的情况下为 ArrayList)。

最近,并发包已经发布,其中有许多巧妙的实用程序可以解决多线程问题。

The synchronized keyword causes a thread to obtain a lock when entering the method, so that only one thread can execute the method at the same time (for the given object instance, unless it is a static method).

This is frequently called making the class thread-safe, but I would say this is a euphemism. While it is true that synchronization protects the internal state of the Vector from getting corrupted, this does not usually help the user of Vector much.

Consider this:

 if (vector.isEmpty()){
     vector.add(data);
 }

Even though the methods involved are synchronized, because they are being locked and unlocked individually, two unfortunately timed threads can create a vector with two elements.

So in effect, you have to synchronize in your application code as well.

Because method-level synchronization is a) expensive when you don't need it and b) insufficient when you need synchronization, there are now un-synchronized replacements (ArrayList in the case of Vector).

More recently, the concurrency package has been released, with a number of clever utilities that take care of multi-threading issues.

瀞厅☆埖开 2024-08-01 18:22:58

概述

Java 中的 Synchronized 关键字与线程安全有关,即多个线程读取或写入同一个变量时。
这可以直接发生(通过访问相同的变量)或间接发生(通过使用一个类,该类使用另一个访问相同变量的类)。

synchronized 关键字用于定义一个代码块,其中多个线程可以以安全的方式访问同一个变量。

更深入的

语法方面,synchronized 关键字采用一个 Object 作为参数(称为锁定对象),然后后面跟着一个 {代码块}

  • 当执行过程中遇到此关键字时,当前线程会尝试“锁定/获取/拥有”(随意选择)锁定对象,并在获取锁定后执行关联的代码块。

  • 使用相同锁对象类似地在同步代码块内执行代码的每个其他线程都是可见的。

  • 一次只有一个线程可以持有锁,在此期间所有其他尝试获取同一锁对象的线程都将等待(暂停执行)。 当执行退出同步代码块时,锁将被释放。

同步方法:

在方法定义中添加synchronized关键字等于将整个方法体包装在同步代码块中,锁定对象this (对于实例方法)ClassInQuestion.getClass() (对于类方法)

- 实例方法是没有 static 关键字的方法。
- 类方法是具有 static 关键字的方法。

技术

如果没有同步,则无法保证读取和写入发生的顺序,可能会导致变量留下垃圾。< br>
(例如,一个变量可能最终有一半的位由一个线程写入,一半的位由另一个线程写入,使该变量处于两个线程都未尝试写入的状态,但混合在一起的混乱两者。)

在另一个线程读取之前(挂钟时间)在线程中完成写入操作是不够的,因为硬件可能已经缓存了变量的值,并且读取线程将看到缓存的值值而不是写入的内容。

结论

因此,在 Java 的情况下,您必须遵循 Java 内存模型以确保不会发生线程错误。
换句话说:使用同步、原子操作或在幕后为您使用它们的类。

来源

http://docs.oracle.com/javase/specs/jls/se8 /html/index.html
Java® 语言规范,2015-02-13

Overview

Synchronized keyword in Java has to do with thread-safety, that is, when multiple threads read or write the same variable.
This can happen directly (by accessing the same variable) or indirectly (by using a class that uses another class that accesses the same variable).

The synchronized keyword is used to define a block of code where multiple threads can access the same variable in a safe way.

Deeper

Syntax-wise the synchronized keyword takes an Object as it's parameter (called a lock object), which is then followed by a { block of code }.

  • When execution encounters this keyword, the current thread tries to "lock/acquire/own" (take your pick) the lock object and execute the associated block of code after the lock has been acquired.

  • Any writes to variables inside the synchronized code block are guaranteed to be visible to every other thread that similarly executes code inside a synchronized code block using the same lock object.

  • Only one thread at a time can hold the lock, during which time all other threads trying to acquire the same lock object will wait (pause their execution). The lock will be released when execution exits the synchronized code block.

Synchronized methods:

Adding synchronized keyword to a method definition is equal to the entire method body being wrapped in a synchronized code block with the lock object being this (for instance methods) and ClassInQuestion.getClass() (for class methods).

- Instance method is a method which does not have static keyword.
- Class method is a method which has static keyword.

Technical

Without synchronization, it is not guaranteed in which order the reads and writes happen, possibly leaving the variable with garbage.
(For example a variable could end up with half of the bits written by one thread and half of the bits written by another thread, leaving the variable in a state that neither of the threads tried to write, but a combined mess of both.)

It is not enough to complete a write operation in a thread before (wall-clock time) another thread reads it, because hardware could have cached the value of the variable, and the reading thread would see the cached value instead of what was written to it.

Conclusion

Thus in Java's case, you have to follow the Java Memory Model to ensure that threading errors do not happen.
In other words: Use synchronization, atomic operations or classes that use them for you under the hoods.

Sources

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Java® Language Specification, 2015-02-13

維他命╮ 2024-08-01 18:22:58

可以把它想象成一种十字转门,就像你在足球场上看到的那样。 有平行的人流想要进去,但在十字转门处他们是“同步”的。 一次只有一个人可以通过。 所有想要通过的人都可以,但他们可能必须等到他们能够通过为止。

Think of it as a kind of turnstile like you might find at a football ground. There are parallel steams of people wanting to get in but at the turnstile they are 'synchronised'. Only one person at a time can get through. All those wanting to get through will do, but they may have to wait until they can go through.

澜川若宁 2024-08-01 18:22:58

1. 什么是synchronized关键字?

同步块或方法可以防止线程干扰并确保数据一致。 在任何时间点,只有一个线程可以通过获取锁来访问同步块或方法(临界区)。 其他线程将等待锁释放才能访问关键部分

2. 方法何时同步?

当您将 synchronized 添加到方法定义或声明时,方法就会同步。 您还可以在方法中同步特定的代码块。

3. 从编程和逻辑上讲这是什么意思?

这意味着只有一个线程可以通过获取锁来访问临界区。 除非该线程释放该锁,否则所有其他线程都必须等待获取锁。 如果不获取锁,他们就无法进入关键部分

程序员有责任识别应用程序中的关键部分并相应地对其进行保护。 Java提供了一个框架来保护你的应用程序,但是保护哪些部分是程序员的责任。

使方法同步有两个效果

首先,同一对象上的同步方法的两次调用不可能交错。

其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立发生之前关系。

这保证了对象状态的更改对所有线程都是可见的。

在以下位置寻找同步的其他替代方法:

避免在 Java 中同步(this)?

1. What is the synchronized keyword?

Synchronized blocks or methods prevents thread interference and make sure that data is consistent. At any point of time, only one thread can access a synchronized block or method (critical section) by acquiring a lock. Other thread(s) will wait for release of lock to access critical section.

2. When are methods synchronized?

Methods are synchronized when you add synchronized to method definition or declaration. You can also synchronize a particular block of code with-in a method.

3. What does it mean pro grammatically and logically?

It means that only one thread can access critical section by acquiring a lock. Unless this thread release this lock, all other thread(s) will have to wait to acquire a lock. They don't have access to enter critical section with out acquiring lock.

It's programmer responsibility to identify critical section(s) in application and guard it accordingly. Java provides a framework to guard your application, but which sections to be guarded is the responsibility of programmer.

Making methods synchronized has two effects:

First, it is not possible for two invocations of synchronized methods on the same object to interleave.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object.

This guarantees that changes to the state of the object are visible to all threads.

Look for other alternatives to synchronization in :

Avoid synchronized(this) in Java?

何处潇湘 2024-08-01 18:22:58

同步普通方法相当于
Synchronized 语句(使用此)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized 静态方法 等价于 Synchronized 语句(使用类)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

Synchronized 语句(使用变量)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

For synchronized< /code>,我们有同步方法同步语句。 不过,同步方法同步语句类似,因此我们只需要了解同步语句即可。

=> 基本上,我们认为

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

这 2 点有助于理解synchronized

  • 每个对象/类都有一个与其关联的内在锁
  • 当线程调用同步语句时,它会自动获取该同步语句对象的内在锁,并在方法返回时释放它。 只要一个线程拥有内在锁没有其他线程就可以获取SAME锁=> 线程安全。

=>
线程A调用synchronized(this){//代码1} =>; 所有具有 synchronized(this) 的块代码(在类内部)和所有同步普通方法(在类内部)都被锁定,因为 SAME 锁。 它将在线程 A 解锁后执行(“// code 1”完成)。

此行为类似于 synchronized(a variable){// code 1}synchronized(class)

相同的锁 => 锁(不依赖哪个方法?或者哪个语句?)

使用同步方法还是同步语句?

我更喜欢同步语句,因为它更具可扩展性。 例如,将来您只需要同步方法的一部分。 例如,您有 2 个同步方法,并且它们彼此没有任何相关,但是当线程运行一个方法时,它将阻塞另一个方法(它可以通过使用 synchronized 来阻止(变量))。

不过,apply Synchronized方法很简单,代码看起来也很简单。 对于某个类,只有1个同步方法,或者该类中的所有同步方法彼此相关=> 我们可以使用synchronized方法使代码更短且易于理解

注意

(它与synchronized没有太大关系,它是对象和类或非静态和非静态之间的区别静止的)。

  • 当您使用synchronized或普通方法或synchronized(this)synchronized(non-staticvariable)时,它将基于每个对象实例进行同步。
  • 当您使用synchronized或静态方法或synchronized(class)synchronized(static variable)时,它将基于类

参考

进行同步https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
https://docs.oracle.com/javase/tutorial/essential/concurrency /locksync.html

希望有帮助

Synchronized normal method equivalent to
Synchronized statement (use this)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static method equivalent to Synchronized statement (use class)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

Synchronized statement (using variable)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

For synchronized, we have both Synchronized Methods and Synchronized Statements. However, Synchronized Methods is similar to Synchronized Statements so we just need to understand Synchronized Statements.

=> Basically, we will have

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

Here is 2 think that help understanding synchronized

  • Every object/class have an intrinsic lock associated with it.
  • When a thread invokes a synchronized statement, it automatically acquires the intrinsic lock for that synchronized statement's object and releases it when the method returns. As long as a thread owns an intrinsic lock, NO other thread can acquire the SAME lock => thread safe.

=>
When a thread A invokes synchronized(this){// code 1} => all the block code (inside class) where have synchronized(this) and all synchronized normal method (inside class) is locked because SAME lock. It will execute after thread A unlock ("// code 1" finished).

This behavior is similar to synchronized(a variable){// code 1} or synchronized(class).

SAME LOCK => lock (not depend on which method? or which statements?)

Use synchronized method or synchronized statements?

I prefer synchronized statements because it is more extendable. Example, in future, you only need synchronized a part of method. Example, you have 2 synchronized method and it don't have any relevant to each other, however when a thread run a method, it will block the other method (it can prevent by use synchronized(a variable)).

However, apply synchronized method is simple and the code look simple. For some class, there only 1 synchronized method, or all synchronized methods in the class in relevant to each other => we can use synchronized method to make code shorter and easy to understand

Note

(it not relevant to much to synchronized, it is the different between object and class or none-static and static).

  • When you use synchronized or normal method or synchronized(this) or synchronized(non-static variable) it will synchronized base on each object instance.
  • When you use synchronized or static method or synchronized(class) or synchronized(static variable) it will synchronized base on class

Reference

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Hope it help

泼猴你往哪里跑 2024-08-01 18:22:58

以下是来自Java 教程的解释。

考虑以下代码:

公共类 SynchronizedCounter { 
      私有 int c = 0; 

      公共同步无效增量(){ 
          c++; 
      } 

      公共同步无效减量(){ 
          C - ; 
      } 

      公共同步 int value() { 
          返回c; 
      } 
  } 
  

如果 countSynchronizedCounter 的实例,那么使这些方法同步有两个效果:

  • 首先,同一对象上的同步方法的两次调用不可能交错。 当一个线程正在执行某个对象的同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(挂起执行),直到第一个线程处理完该对象为止。
  • 其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立发生之前关系。 这保证了对象状态的更改对所有线程都可见。

Here is an explanation from The Java Tutorials.

Consider the following code:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

if count is an instance of SynchronizedCounter, then making these methods synchronized has two effects:

  • First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
  • Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
救赎№ 2024-08-01 18:22:58

据我了解,同步基本上意味着编译器在您的方法周围编写一个monitor.enter和monitor.exit。 因此,它可能是线程安全的,具体取决于它的使用方式(我的意思是,您可以使用同步方法编写一个对象,但该对象不是线程安全的,具体取决于您的类的用途)。

To my understanding synchronized basically means that the compiler write a monitor.enter and monitor.exit around your method. As such it may be thread safe depending on how it is used (what I mean is you can write an object with synchronized methods that isn't threadsafe depending on what your class does).

迷你仙 2024-08-01 18:22:58

其他答案缺少的是一个重要方面:内存屏障。 线程同步基本上由两个部分组成:序列化和可见性。 我建议大家去谷歌搜索“jvm内存屏障”,因为这是一个不平凡且极其重要的主题(如果您修改多个线程访问的共享数据)。 完成此操作后,我建议查看 java.util.concurrent 包的类,它们有助于避免使用显式同步,这反过来又有助于保持程序简单高效,甚至可能防止死锁。

其中一个示例是 ConcurrentLinkedDeque。 与命令模式一起,它允许通过将命令填充到并发队列中来创建高效的工作线程-- 不需要显式同步,不会出现死锁,不需要显式 sleep(),只需通过调用 take() 轮询队列即可。

简而言之:当您启动线程、线程结束、读取易失性变量、解锁监视器(留下同步块/函数)等时,“内存同步”会隐式发生。这种“同步”影响(在某种意义上“刷新”)所有在该特定操作之前完成的写入。 对于上述 ConcurrentLinkedDeque ,文档“说”:

内存一致性影响:与其他并发集合一样,
将对象放入之前线程中的操作
ConcurrentLinkedDeque 发生在 访问后的操作
或从另一个 ConcurrentLinkedDeque 中删除该元素
线程。


这种隐式行为是一个有点有害的方面,因为大多数没有太多经验的 Java 程序员只会因此而采取很多既定的做法。 然后,在 Java 没有执行它在生产环境中“应该”执行的操作(其中存在不同的工作负载)之后,突然遇到了这个线程,而且测试并发问题非常困难。

What the other answers are missing is one important aspect: memory barriers. Thread synchronization basically consists of two parts: serialization and visibility. I advise everyone to google for "jvm memory barrier", as it is a non-trivial and extremely important topic (if you modify shared data accessed by multiple threads). Having done that, I advise looking at java.util.concurrent package's classes that help to avoid using explicit synchronization, which in turn helps keeping programs simple and efficient, maybe even preventing deadlocks.

One such example is ConcurrentLinkedDeque. Together with the command pattern it allows to create highly efficient worker threads by stuffing the commands into the concurrent queue -- no explicit synchronization needed, no deadlocks possible, no explicit sleep() necessary, just poll the queue by calling take().

In short: "memory synchronization" happens implicitly when you start a thread, a thread ends, you read a volatile variable, you unlock a monitor (leave a synchronized block/function) etc. This "synchronization" affects (in a sense "flushes") all writes done before that particular action. In the case of the aforementioned ConcurrentLinkedDeque, the documentation "says":

Memory consistency effects: As with other concurrent collections,
actions in a thread prior to placing an object into a
ConcurrentLinkedDeque happen-before actions subsequent to the access
or removal of that element from the ConcurrentLinkedDeque in another
thread.

This implicit behavior is a somewhat pernicious aspect because most Java programmers without much experience will just take a lot as given because of it. And then suddenly stumble over this thread after Java isn't doing what it is "supposed" to do in production where there is a different work load -- and it's pretty hard to test concurrency issues.

天赋异禀 2024-08-01 18:22:58

同步仅仅意味着如果在特定对象上使用同步块,则与单个对象关联的多个线程可以防止脏读和脏写。 为了让您更清楚,让我们举个例子:

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

我们创建了两个 MyRunnable 类对象,runnable1 与线程 1 和线程 3 共享。 runnable2 仅与线程 2 共享。
现在,当 t1 和 t3 在没有使用同步的情况下启动时,PFB 输出表明线程 1 和 3 同时影响 var 值,其中对于线程 2 来说,var 有自己的内存。

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

使用 Synchronzied,线程 3 在所有情况下都会等待线程 1 完成。 获取了两个锁,一个在由线程 1 和线程 3 共享的 runnable1 上,另一个在仅由线程 2 共享的 runnable2 上。

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

Synchronized simply means that multiple threads if associated with single object can prevent dirty read and write if synchronized block is used on particular object. To give you more clarity , lets take an example :

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

We've created two MyRunnable class objects , runnable1 being shared with thread 1 and thread 3 & runnable2 being shared with thread 2 only.
Now when t1 and t3 starts without synchronized being used , PFB output which suggest that both threads 1 and 3 simultaneously affecting var value where for thread 2 , var has its own memory.

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

Using Synchronzied, thread 3 waiting for thread 1 to complete in all scenarios. There are two locks acquired , one on runnable1 shared by thread 1 and thread 3 and another on runnable2 shared by thread 2 only.

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18
旧人九事 2024-08-01 18:22:58

在java中为了防止多个线程操作共享变量,我们使用synchronized关键字。 让我们借助以下示例来理解它:

在示例中,我定义了两个线程并将它们命名为增量和减量。 增量线程增加共享变量(counter)的值,增量与减量线程减少的量相同,即增加 5000 倍(结果为 5000 + 0 = 5000),减少 5000 倍(结果为 5000 + 0 = 5000)。结果为 5000 - 5000 = 0)。

没有synchronized关键字的程序:

class SynchronizationDemo {

    public static void main(String[] args){

        Buffer buffer = new Buffer();                   

        MyThread incThread = new MyThread(buffer, "increment");
        MyThread decThread = new MyThread(buffer, "decrement"); 

        incThread.start();
        decThread.start();  
       
        try {
          incThread.join();
          decThread.join();
        }catch(InterruptedException e){ }

        System.out.println("Final counter: "+buffer.getCounter());
    }
}

class Buffer {
    private int counter = 0; 
    public void inc() { counter++; }
    public void dec() { counter--; } 
    public int getCounter() { return counter; }
}

class MyThread extends Thread {

    private String name;
    private Buffer buffer;

    public MyThread (Buffer aBuffer, String aName) {            
        buffer = aBuffer; 
        name = aName; 
    }

    public void run(){
        for (int i = 0; i <= 5000; i++){
            if (name.equals("increment"))
                buffer.inc();
            else
                buffer.dec();                           
        }
    }
}

如果我们运行上述程序,我们期望缓冲区的值相同,因为以相同的量递增和递减缓冲区将导致我们开始时的初始值正确的 ?。 让我们看看输出:

在此处输入图像描述

正如您所看到的,无论我们运行程序多少次,我们都会得到不同的结果,原因是每个线程同时操作计数器。 如果我们能够设法让一个线程首先递增共享变量,然后第二次递减它,反之亦然,那么我们将获得正确的结果,这正是使用 synchronized 关键字可以完成的结果在 Bufferincdec 方法之前添加 synchronized 关键字,如下所示:

Program with synchronized 关键字:

// rest of the code

class Buffer {
    private int counter = 0; 
    // added synchronized keyword to let only one thread
    // be it inc or dec thread to manipulate data at a time
    public synchronized void inc() { counter++; }
    public synchronized void dec() { counter--; } 
    public int getCounter() { return counter; }
}

// rest of the code

和输出:

在此处输入图像描述

无论我们运行多少次,我们都会得到与 0 相同的输出

In java to prevent multiple threads manipulating a shared variable we use synchronized keyword. Lets understand it with help of the following example:

In the example I have defined two threads and named them increment and decrement. Increment thread increases the value of shared variable (counter) by the same amount the decrement thread decreases it i.e 5000 times it is increased (which result in 5000 + 0 = 5000) and 5000 times we decrease (which result in 5000 - 5000 = 0).

Program without synchronized keyword:

class SynchronizationDemo {

    public static void main(String[] args){

        Buffer buffer = new Buffer();                   

        MyThread incThread = new MyThread(buffer, "increment");
        MyThread decThread = new MyThread(buffer, "decrement"); 

        incThread.start();
        decThread.start();  
       
        try {
          incThread.join();
          decThread.join();
        }catch(InterruptedException e){ }

        System.out.println("Final counter: "+buffer.getCounter());
    }
}

class Buffer {
    private int counter = 0; 
    public void inc() { counter++; }
    public void dec() { counter--; } 
    public int getCounter() { return counter; }
}

class MyThread extends Thread {

    private String name;
    private Buffer buffer;

    public MyThread (Buffer aBuffer, String aName) {            
        buffer = aBuffer; 
        name = aName; 
    }

    public void run(){
        for (int i = 0; i <= 5000; i++){
            if (name.equals("increment"))
                buffer.inc();
            else
                buffer.dec();                           
        }
    }
}

If we run the above program we expect value of buffer to be same since incrementing and decrementing the buffer by same amount would result in initial value we started with right ?. Lets see the output:

enter image description here

As you can see no matter how many times we run the program we get a different result reason being each thread manipulated the counter at the same time. If we could manage to let the one thread to first increment the shared variable and then second to decrement it or vice versa we will then get the right result that is exactly what can be done with synchronized keyword by just adding synchronized keyword before the inc and dec methods of Buffer like this:

Program with synchronized keyword:

// rest of the code

class Buffer {
    private int counter = 0; 
    // added synchronized keyword to let only one thread
    // be it inc or dec thread to manipulate data at a time
    public synchronized void inc() { counter++; }
    public synchronized void dec() { counter--; } 
    public int getCounter() { return counter; }
}

// rest of the code

and the output:

enter image description here

no matter how many times we run it we get the same output as 0

痞味浪人 2024-08-01 18:22:58

Java同步

易失性[关于] => Java中的synchronized

synchronized块是多线程中的监视器。 具有相同对象/类的同步块只能由单个线程执行,所有其他线程都在等待。 它可以帮助解决竞争条件[关于]情况。

Java 5 通过支持 happens-before 扩展了synchronized [关于]

监视器的解锁(同步块或方法退出)发生在同一监视器的每个后续锁定(同步块或方法入口)之前。

下一步是java.util.concurrent

Java synchronized

volatile[About] => synchronized

synchronized block in Java is a monitor in multithreading. synchronized block with the same object/class can be executed by only single thread, all others are waiting. It can help with race condition[About] situation.

Java 5 extended synchronized by supporting happens-before[About]

An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor.

The next step is java.util.concurrent

究竟谁懂我的在乎 2024-08-01 18:22:58

同步简单意味着没有两个线程可以同时访问块/方法。 当我们说类的任何块/方法是同步的时,这意味着一次只有一个线程可以访问它们。 在内部,尝试访问它的线程首先会对该对象加锁,只要该锁不可用,其他线程就无法访问该类实例的任何同步方法/块。

请注意,另一个线程可以访问未定义为同步的同一对象的方法。 线程可以通过调用来释放锁

Object.wait()

synchronized simple means no two threads can access the block/method simultaneously. When we say any block/method of a class is synchronized it means only one thread can access them at a time. Internally the thread which tries to access it first take a lock on that object and as long as this lock is not available no other thread can access any of the synchronized methods/blocks of that instance of the class.

Note another thread can access a method of the same object which is not defined to be synchronized. A thread can release the lock by calling

Object.wait()
泅人 2024-08-01 18:22:58

synchronized”关键字是为了实现线程安全。 它将同步块或方法的访问限制为一次只能有一个线程,有效地防止多线程程序中的数据不一致。

何时使用方法同步

在处理数据结构等共享资源时,方法同步就变得很有必要。 它可以防止数据损坏,特别是在一次只能运行一个线程的关键部分。 对于用于多线程使用的类来说,维护线程安全也至关重要。

理解编程和逻辑含义

从编程的角度来看,Java 的同步确保只有一个线程可以通过获取和释放锁来访问同步代码。 从逻辑上讲,它在多线程环境中强制执行数据一致性和完整性。

The "synchronized" keyword is for achieving thread safety. It restricts access to a synchronized block or method to just one thread at a time, effectively preventing data inconsistencies in multi-threaded programs.

When to Use Method Synchronization

Method synchronization becomes necessary when dealing with shared resources such as data structures. It safeguards against data corruption, especially in critical sections where only one thread should operate at a time. It's also vital in classes intended for multi-threaded use to maintain thread safety.

Understanding the Programmatic and Logical Implications

From a programmatic perspective, Java's synchronization ensures that only one thread can access synchronized code by acquiring and releasing locks. Logically, it enforces data consistency and integrity in multi-threaded environments.

夜深人未静 2024-08-01 18:22:58

Synchronized是Java中的一个关键字,用于在多线程环境中使关系发生在之前,以避免内存不一致和线程干扰错误。

synchronized is a keyword in Java which is used to make happens before relationship in multithreading environment to avoid memory inconsistency and thread interference error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文