Java 当一个作者说“我不知道”是什么意思;两个线程试图同时执行一段代码;?

Java 当一个作者说“我不知道”是什么意思;两个线程试图同时执行一段代码;?,java,multithreading,concurrency,thread-safety,java-threads,Java,Multithreading,Concurrency,Thread Safety,Java Threads,所以我在看一篇文章,我无法理解下面的陈述 public class Counter { private int counter = 0; public int get() { return counter; } public void set(int n) { counter = n; } public void increment() { set(get() + 1); } } 如果两个线程试图同时执行increment(),会发生什么情况?计数器可

所以我在看一篇文章,我无法理解下面的陈述

public class Counter {
  private int counter = 0;

  public int  get()      { return counter; }
  public void set(int n) { counter = n; }
  public void increment() {
    set(get() + 1);
  }
}
如果两个线程试图同时执行increment(),会发生什么情况?计数器可能会增加1或2


我的疑问是,如果线程a第一次执行上述语句,那么get()将返回0,set increment将其设置为1。只有在线程A完成执行或进入睡眠状态后,线程B才能开始执行?为什么线程A和线程B可以同时执行一段代码?
如何将计数器增加2?

当共享资源被2个或更多线程修改,并且对该资源的访问未同步时,无法保证两个线程具有相同的资源视图,因此修改的结果可能因视图不一致而不同。这称为
交错

要解决这个问题,只需使用互斥来确保两个线程不能通过同步对每个方法的访问来同时修改对象。这包括setter和getter


为什么线程A和线程B可以同时执行一段代码

因为这就是线程的全部意义。这就是线程的用途:线程的存在使得程序中的不同“活动”可以彼此发生

计数器如何增加2

这不是你想要的吗?如果
counter.increment()
被调用两次,您不想让某个
计数器的值增加两次吗?在这种情况下,您不希望计数器的值只增加1

有一种方法可以实现。假设
计数器==3

Thread A                               Thread B
enters increment()
calls get(), get returns 3             enters increment()
computes new value, 4
                                       calls get(), get returns 3
calls set(4).                          computes new value, 3+1=4
returns from increment()               calls set(4)
                                       returns from increment()
一个有经验的Java程序员在查看
计数器时会说它不是


简而言之,“线程安全”类是一个保证以某些有用方式运行的类,即使不同线程同时调用它的方法也是如此。例如,线程安全的
计数器
类将记录,并确保无论有多少线程同时调用其
increment()
方法,在它们全部返回后,最终结果是计数器值将增加等于调用次数的量

“为什么线程A和线程B可以同时执行一段代码?”您的CPU有多少个内核?您的计算机有多少个处理器?即使只有一个内核,线程也不一定要执行完整的方法调用,直到它必须允许执行不同的代码(无论是您的代码,还是需要在您的计算机内部运行的其他代码)。然而,从这一点来看,需要多次读/写的操作(如i++,相当于i=i+1,它进行一次读和一次写)不是原子的,因为另一个线程可能在读和写之间向i写入。"我的问题是-如果线程A在0.01秒时将一个对象初始化为变量,那么线程B为什么也可以在0.01秒时将同一个对象初始化为变量。我这里缺少什么?既然代码只是010101,那么如果某个线程在某个时间执行某个内存块,那么另一个线程为什么可以访问和执行e在完全相同的时间使用相同的内存?@ks55NGMC从概念上讲,您认为是什么阻止两个线程同时执行相同的事情?@ks55NGMC一些不正确的线程交互非常罕见,但这也使得它们很难调试。最好在问题发生之前修复它们。