All dieses Verhalten ist abhängig von der Implementierung. Der Garbage Collector läuft in seinem eigenen asynchronen Thread, der nichts mit dem Synchronisationsverhalten Ihres Programms zu tun hat. Sie wissen einfach nicht, wann das Array, auf das data1 verweist, vom Garbage Collector entsorgt wird - Sie können nur hoffen, dass dies in einer "vernünftigen" Zeitspanne geschieht, nachdem es aus dem Anwendungsbereich verschwunden ist bzw. alle Verweise auf das Array gelöscht wurden.
Wenn Sie sich Sorgen machen, dass Ihnen der Speicher in Ihrem Programm ausgeht, können Sie explizit versuchen, mit System.gc() einen Garbage-Collection-Zyklus auszulösen. Aber auch dies garantiert nicht, dass genügend Speicher verfügbar ist, wenn Sie Daten2 zuweisen. Der Aufruf von System.gc() ist lediglich ein Hinweis an die Laufzeitumgebung, dass Sie jetzt einen Garbage-Collection-Zyklus durchführen lassen möchten.
In Java ist die Zuweisung und Freigabe von Speicher nicht-deterministisch. Der Garbage Collector wird ausgeführt, wenn er läuft, und man kann ihn nicht auf Programmebene steuern. Es gibt keine relevanten Unterschiede zwischen den von Ihnen geposteten Codeschnipseln, da das Verhalten des Garbage Collectors nicht-deterministisch ist und der genaue Zeitpunkt, zu dem er ausgelöst wird, von der Implementierung und dem System abhängt. Manchmal ist dies ein Problem für Ihre Anwendung - zum Beispiel wenn es sich um ein Betriebssystem oder ein eingebettetes Gerät mit begrenztem Speicher handelt - und Sie müssen in C++ oder einer anderen Sprache programmieren, in der die Speicherverwaltung deterministisch ist. Die meisten von uns vertrauen jedoch einfach darauf, dass der Garbage Collector sich einigermaßen vernünftig verhält, und das ist für die meisten Zwecke gut genug - obwohl man, wie Sie sehen, auch künstlichen Code erstellen kann, der Probleme verursacht.
Update: Peinlich. Wie mich ein paar andere Kommentatoren daran erinnert haben, wird ein Garbage Collection-Zyklus explizit ausgelöst, bevor der JVM einen OutOfMemory-Fehler auslöst. Allerdings ist das Verhalten immer noch nicht-deterministisch: als dieser Link erklärt, garantiert der JVM nicht, dass alle toten Objekte in einem Garbage Collection-Zyklus entdeckt werden.