多线程

Multi threading

我有一个关于多线程的想法,但我从未付诸实践。所以,当我看到我的应用程序在工作时......我没有看到任何 class 扩展线程创建 Thread。因此,当 2 个对象试图同时访问一个变量时,使用 synchronized 关键字。我们使用 synchronized 来避免冲突。

示例:

public class Test {

    private static int count = 0;

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

如果测试 class 被对象使用,那么将 synchronized 添加到 incrementcount() 是有意义的。但是当你不扩展 ThreadRunnable 那么写 synchronized.

有什么用

Synchronized 不适用于线程或 Runnable,它用于被多个线程访问的数据结构,以确保每个线程以不破坏其数据的方式访问它们。你自己的例子是一个基本的例子,其中计数以一种非线程安全的方式增加(using ++, see this question),所以它需要锁定以确保一次只有一个线程可以增加它。

如果有其他代码访问计数,它也需要同步,以便它可以看到计数的更新。如果您所做的只是递增计数器,那么使用 class 更有意义,例如 java.util.concurrent.atomic.AtomicInteger,并且您可以完全不使用 synchronized 关键字。

为了使使用 synchronized 有意义,它确实假设有多个线程。即使您自己的代码不创建新线程,也可能存在多个线程调用您的代码的情况(例如在 servlet 容器中,容器管理一个线程池并为每个传入请求分配一个线程)。

i++,看似单条指令,其实是多条指令:

  1. 将临时变量设置为 1+i
  2. 设置变量i为临时变量

但是,假设执行i++的线程在步骤1之后被中断,中断线程也调用i++。然后,会发生这样的事情:

(假设i=1

  1. 原线程: 将临时变量 1 设置为 1+i,或 2
  2. 中断线程: 将临时变量 2 设置为 i+1,也 2
  3. 中断线程:i设置为临时变量2。现在i=2
  4. 原帖:i设置为临时变量1。现在i=2

问题是如果i++调用了两次,应该是3,而不是2


A synchronized void 将锁定变量 i 直到整个 void 完成执行。例如:

  1. 原线程: 将临时变量 1 设置为 1+i,或 2。锁定变量 i.
  2. 中断线程: 尝试将临时变量 2 设置为 i+1,但由于变量 i
  3. 的锁定而等待
  4. 原帖:i设置为临时变量1。现在i=2。变量 i 现已解锁。
  5. 中断线程: "notices" i 已解锁,因此将临时变量2设置为 i+13.
  6. 中断线程:i 设置为 3,这是预期的行为。

synchronized voids 基本上临时锁定变量以避免混淆程序的执行。

A class 不需要 extend Threadimplements Runnable 将其方法标记为同步以防止多线程访问

您的 class 可能是某个其他线程 class 的参数,并且该线程 class 可能有多个实例。为了提供强一致性的数据,您必须保护代码和数据的关键部分。

只需更改您的代码示例,如下所示。

我在对象级别而不是 class 级别演示“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();  
        }
    }
}

您的 class Test 已作为参数传递给线程 MyRunnable。现在您已经创建了多个线程实例。如果没有 synchronized 关键字,输出将不可预测,如下所示。

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

如果我改变

public void incrementCount() {

public synchronized void incrementCount() {

输出为:

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

换句话说,您已将方法设为 static synchronizedThat means lock is maintained at class level instead of object level.

查看 oracle 文档 page 以获得更好的理解。

缺少“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();  
        }
    }
}

输出:

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

制作后

public static void incrementCount() {

ppublic static synchronized void incrementCount() {

输出:

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

在此示例中,与之前不同,我们创建了 10 个不同的 Test 个实例。