数据竞争和先行原则

    先行原则规定了先行的操作对后续的操作可见,有效解决了数据竞争问题。数据竞争问题发生在当变量被多个线程读时,同时至少有一个线程在对这个变量进行写,那么写入的变量不一定能够及时被其他线程看见,甚至永远也不能被其他线程看见。

    从这里就可以看出,“先行”其实规定的是“可见性”问题,它和操作(读、写、方法调用等)发生的时间先后是两个概念,时间上先发生的,对后发生的不一定可见(当然,没发生的事情,必然不可见)。再次强调,“先行”强调的是“可见性”。

java虚拟机规范有这样的说明:

Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.

If we have two actions x and y, we write hb(x, y) to indicate that x happens-before y.

  • If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).

  • There is a happens-before edge from the end of a constructor of an object to the start of a finalizer (§12.6) for that object.

  • If an action x synchronizes-with a following action y, then we also have hb(x, y).

  • If hb(x, y) and hb(y, z), then hb(x, z).

The wait methods of class Object (§17.2.1) have lock and unlock actions associated with them; their happens-before relationships are defined by these associated actions.

It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.

For example, the write of a default value to every field of an object constructed by a thread need not happen before the beginning of that thread, as long as no read ever observes that fact.

More specifically, if two actions share a happens-before relationship, they do not necessarily have to appear to have happened in that order to any code with which they do not share a happens-before relationship. Writes in one thread that are in a data race with reads in another thread may, for example, appear to occur out of order to those reads.

The happens-before relation defines when data races take place.

A set of synchronization edges, S, is sufficient if it is the minimal set such that the transitive closure of S with the program order determines all of the happens-before edges in the execution. This set is unique.

It follows from the above definitions that:

  • An unlock on a monitor happens-before every subsequent lock on that monitor.

  • A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

  • A call to start() on a thread happens-before any actions in the started thread.

  • All actions in a thread happen-before any other thread successfully returns from a join() on that thread.

  • The default initialization of any object happens-before any other actions (other than default-writes) of a program.

When a program contains two conflicting accesses (§17.4.1) that are not ordered by a happens-before relationship, it is said to contain a data race.

The semantics of operations other than inter-thread actions, such as reads of array lengths (§10.7), executions of checked casts (§5.5, §15.16), and invocations of virtual methods (§15.12), are not directly affected by data races.

Therefore, a data race cannot cause incorrect behavior such as returning the wrong length for an array.

A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.

原文地址:https://www.cnblogs.com/JMLiu/p/8619650.html