简体   繁体   English

多线程

[英]Multi threading

I have an idea about multi-threading but I never worked on it. 我对多线程有一个想法,但我从未尝试过。 So, when I see my application at work... I haven't seen any class extending Thread creating a Thread . 因此,当我看到我的应用程序在工作时...我没有看到任何扩展Thread的类来创建Thread So, synchronized keyword is used when 2 objects try to access a variable at the same time.. we use synchronized to avoid conflicts. 因此,当2个对象尝试同时访问变量时, synchronized使用synchronized关键字。我们使用synced来避免冲突。

Example: 例:

public class Test {

    private static int count = 0;

    public static synchronized void incrementCount() {
        count++;
    }
} 

If test class was using by an object then it makes sense to add synchronized to incrementcount() . 如果测试类使用由对象然后是有意义的加synchronizedincrementcount() But when you don't extend Thread or Runnable then what's the use of writing synchronized . 但是,当你不延长ThreadRunnable那么有什么用书面synchronized

Synchronized isn't for threads or Runnables, it's used for data structures that are accessed by multiple threads in order to make sure each thread accesses them in a way that doesn't corrupt their data. 同步不适用于线程或Runnable,它用于由多个线程访问的数据结构,以确保每个线程以不破坏其数据的方式访问它们。 Your own example is a rudimentary case of this, where count is incremented in a way that isn't threadsafe ( using ++, see this question ), so it needs locking to make sure only one thread at a time can increment it. 您自己的示例是一个简单的例子,其中count以一种不是线程安全的方式递增( 使用++,请参见此问题 ),因此需要锁定以确保一次仅一个线程可以递增它。

If there's other code that accesses count it also needs to be synchronized so that updates to count are visible to it. 如果还有其他访问count的代码,则还需要同步它,以便可见count的更新。 If all you're doing is incrementing a counter then it makes more sense to use a class like java.util.concurrent.atomic.AtomicInteger , and you can do without the synchronized keyword altogether. 如果您要做的只是增加一个计数器,那么使用java.util.concurrent.atomic.AtomicInteger类的类更有意义,并且您可以完全不使用synced关键字。

For using synchronized to make sense it does assume there are multiple threads. 为了使同步有意义,它确实假定存在多个线程。 Even if your own code doesn't create new threads, there can be cases where multiple threads are calling your code (such as in a servlet container, where the container manages a threadpool and allocates a thread to each incoming request). 即使您自己的代码没有创建新的线程,在某些情况下也可能有多个线程在调用您的代码(例如在servlet容器中,该容器管理线程池并为每个传入请求分配线程)。

A class does not need to extend Thread or implements Runnable to mark it's method as synchronized to protect from multiple thread access 一个类不需要extend Threadimplements Runnable来将其方法标记为已同步,以防止多线程访问

Your class may a parameter to some other thread class and that thread class may have multiple instances. 您的类可能是某个其他线程类的参数,并且该线程类可能具有多个实例。 To provide strong consistency of data, you have protect your critical section of code & data. 为了提供强大的数据一致性,您已经保护了代码和数据的关键部分。

Just change your code example as below. 只需更改您的代码示例,如下所示。

I am demonstrating " synchronized " at object level rather than class level ( static synchronized ) 我在对象级别而非类级别演示“已synchronized ”( static synchronized

class Test {
    private int count = 0;
    public void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        Test t = new Test();
        for ( int i=0; i<10; i++){
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

Your class Test has been passed as a parameter to thread MyRunnable . 您的类Test已作为参数传递给线程MyRunnable Now you have created multiple instances of threads. 现在,您已经创建了多个线程实例。 In absence of synchronized keyword, the output is unpredictable as follows. 在没有synchronized关键字的情况下,输出是不可预测的,如下所示。

java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8

If I change 如果我改变

public void incrementCount() {

to

public synchronized void incrementCount() {

the output is: 输出为:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

On a different note, you have make your method as static synchronized . 另一方面,您已将您的方法设置为static synchronized That means lock is maintained at class level instead of object level.

Have a look at oracle documentation page for better understanding. 请查看oracle文档页面以更好地理解。

Demo of code for absence of " static synchronized " 缺少“ static synchronized ”的代码演示

class Test {
    private static int count = 0;
    public static void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        for ( int i=0; i<10; i++){
            Test t = new Test();
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

output: 输出:

Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6

After making 制作后

public static void incrementCount() {

to

ppublic static synchronized void incrementCount() {

output: 输出:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

In this example, unlike earlier, we have created 10 different Test instances. 在此示例中,与之前不同,我们创建了10个不同的Test实例。

i++ , even though it looks like a single instruction, is actually multiple instructions: i++尽管看起来像一条指令,但实际上是多条指令:

  1. Set a temporary variable to 1+i . 将一个临时变量设置为1+i
  2. Set the variable i to the temporary variable. 将变量i设置为临时变量。

However, suppose the thread that executes i++ is interrupted after step 1 , and the interrupting thread also calls i++ . 但是,假设执行i++的线程在步骤1之后被中断,并且中断线程也调用i++ Then, this would happen: 然后,会发生这种情况:

(Suppose i=1 ) (假设i=1

  1. Original thread: set temporary variable1 to 1+i , or 2 . 原始线程:将临时变量1+i设置为1+i2
  2. Interrupting thread: set temporary variable2 to i+1 , also 2 中断线程:将临时变量2设置为i+1 ,也设置为2
  3. Interrupting thread: set i to temporary variable2. 中断线程:i设置为临时变量2。 Now i=2 现在i=2
  4. Original thread: set i to temporary variable1. 原始线程:i设置为临时变量1。 Now i=2 现在i=2

The problem is that if i++ is called twice, it should be 3 , not 2 . 问题是,如果i++被调用两次,则应该为3 ,而不是2


A synchronized void would put a lock on the variable i until the entire void completes executing. synchronized void将锁定变量i直到整个void完成执行。 For example: 例如:

  1. Original thread: set temporary variable1 to 1+i , or 2 . 原始线程:将临时变量1+i设置为1+i2 Puts a lock on the variable i . 锁定变量i
  2. Interrupting thread: TRIES TO set temporary variable2 to i+1 , but waits because of the lock on variable i 中断线程:尝试将临时变量2设置为i+1 ,但由于变量i的锁定而等待
  3. Original thread: set i to temporary variable1. 原始线程:i设置为临时变量1。 Now i=2 . 现在i=2 The variable i is now unlocked. 变量i现已解锁。
  4. Interrupting thread: "notices" that i has been unlocked, so it sets temporary variable2 to i+1 which is 3 . 中断线程: “通知” i已经解锁,因此它将临时变量2设置为i+1 ,即3
  5. Interrupting thread: sets i to 3 , which is expected behavior. 中断线程:i设置为3 ,这是预期行为。

synchronized void s essentially lock variables temporarily to avoid confusing the program's execution. synchronized void本质上是暂时锁定变量,以避免混淆程序的执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM