Archiv für den Monat: Juli 2015

Noch vor wenigen Jahren habe ich jedem gegenüber meine tiefste Verachtung zum Ausdruck gebracht, der mich zum Thema Festplattengrößen fragte, „wer denn soviel Platz bräuchte“. Jeder, der durch solche und ähnliche Pauschaläußerungen seine gnadenlose Beschränktheit offenbarte, ist mir meine teure Zeit und Hirnkapazität eigentlich nicht wert, erst recht keine selbsternannten IT-„Experten“, die sich dann dummerweise durch solche Sprüche entlarven. Inzwischen würde ich die Thematik vielleicht sogar schon etwas lockerer sehen, denn man ist heute in der wahnsinnig komfortablen Situation, dass man nicht nur exorbitant große Festplatten für wirklich wenig Geld bekommt, sondern auch, dass die bislang – gemessen am Preis pro Gigabyte – unbezahlbaren SSD-Festplatten längst in angenehmere Preisregionen gefallen sind.

Im Grunde genommen bin ich nun zum ersten Mal seit Beginn meiner Nutzung diverser Computer in den späten 80er Jahren nicht mehr ständig auf der Suche nach mehr Speicherplatz. Tatsächlich fällt es jetzt sogar mir als Datenhamster und -messie wirklich schwer, den verfügbaren Speicherplatz zu füllen. Wo ich früher im Prinzip täglich jede Menge Datenkrempel auf große Stapel voller CD-Rohlinge auslagern musste, da die Festplatten immer bis zum Anschlag voll waren, habe ich heute soviel Platz, dass ich mir überhaupt keine Sorgen machen muss. Ich habe sogar derart viel Platz, dass ich mir terabyteweise Redundanz leisten kann – vor 15 Jahren mit dem knappen Taschengeld eines Teenagers undenkbar, und auch vor zehn Jahren mit BAföG kaum machbar. Schlimmer noch, musste ich schon damals im Jahresabstand neue Festplatten hinzukaufen, um nicht Gefahr zu laufen, kostbare Daten löschen zu müssen: 1997 noch mit mickrigen 2,1 Gigabyte, 2005 dann mit gefühlten endlosen 500 GB. Beide waren in ungefähr der gleichen Zeit gefüllt. Das Speicherplatz-Wettrüsten war erstmals mit dem Kauf einer 6 TB-Festplatte Ende 2014 beendet, seitdem kann ich mich entspannt zurücklehnen.

Jahrelang tat sich nichts im Bereich Festplattenkapazitäten. Längst hatte ich Angst, dass bei den 4 TB-Modellen eine unüberwindbare physikalische Grenze erreicht war, quasi das Ende der Fahnenstange. Gleichzeitig änderte sich aber eine ganze Menge bei den immer populärer werdenden SSDs, und daher wollten diesen Umstand die Techniklaien dieser Welt als das (warum auch immer) herbeigesehnte Ende der herkömmlichen Festplatten verstehen. Schaut man sich heute mal bei den üblichen Hardware-Versandhändlern um, so findet man endlich 8 TB-Festplatten für nur noch 250 Euro. Die Technik für 10 TB und sogar 20 TB liegt bereits in den Schubladen der Festplattenhersteller. Solche Festplatten werden bewusst teilweise mit dem Namenszusatz „ARCHIVE“ versehen, da solche Massenspeicher sich in Sachen Zugriffszeiten, sowie Datenübertragungsraten mit den SSDs sowieso nicht messen können. Aber sie haben den gigantischen Vorteil ihrer Kapazität, und den kann noch keine SSD ersetzen. Vielleicht noch eine ganze Weile nicht. Die größten Consumer-SSDs mit 2 TB sind zwar schon im Handel erhältlich, jedoch für knapp 1000 Euro in keinster Weise vergleichbar, meiner Ansicht nach auch dann nicht, wenn man versucht, mit der höheren Geschwindigkeit zu argumentieren.

Aber eines beweist mir die aktuelle Situation dann doch: Noch vor wenigen Monaten las ich in einem Technikforum die Behauptung, dass es technisch nicht möglich sein dürfte, in den kommenden Jahren SSDs mit Kapazitäten jenseits der Terabytegrenze zu bauen, da hierfür extreme Strukturverkleinerungen nötig wären. Inzwischen zweifle ich doch sehr stark an dieser Aussage. Es würde mich schon nicht mehr wundern, wenn die Consumer-SSDs in einigen Jahren mit den magnetischen Festplatten gleichziehen würden. Aber bis es soweit ist, werde ich die verblödeten SSD-Nazis auch weiterhin in die Schranken weisen. Storage ist vielen Menschen bei Festplatten eben deutlich wichtiger als reine Geschwindigkeit.

Da mir im Moment der Sinn nicht ganz nach irgendeinem Politikum steht, worüber ich meinen Senf ausgießen müsste, werde ich vorerst noch mehr Softwareentwickler-Kram posten, mit dem ich die geneigten, aber uninteressierten Leser erfolgreich abschrecken kann. Wir danken für Ihr Verständnis.

Wer sich im Internet gezielt über aktives Rendering mittels Canvas in Java informiert, also etwas, das direkt im Zusammenhang mit Java-Spieleentwicklung steht, der wird wahrscheinlich irgendwann über die Methode sync() in java.awt.Toolkit stolpern, also meistens in der Form Toolkit.getDefaultToolkit().sync(). Nun gehe ich stark davon aus, dass die meisten Entwickler diese Codeschnipsel als gegeben ansehen und 1:1 in ihre eigene Klasse einfügen, da sie wahrscheinlich vielfach erprobt sind. So war das bei mir anfangs leider auch. In einem eigenen Render-Thread habe ich Bilder gerendert und anschließend brav das Toolkit „synchronisiert“, was laut Dokumentation irgendwie „gut für Animationen“ ist.

Seit der Umstellung auf aktives Rendering jedoch hatte ich plötzlich Schwierigkeiten damit, den Render-Thread mittels interrupt() vorzeitig zu stoppen, also etwa wenn der Nutzer das Rendering über das Menü beendet oder wenn ein bestimmtes Ereignis auftritt. Zuvor war das nie ein Problem gewesen. Neuerdings läuft der Thread in drei von vier Fällen einfach weiter, sobald ich ihn gezielt unterbrechen will. Das war eine mittlere Katastrophe, denn ich konnte mich jetzt nicht mehr darauf verlassen, dass das Programm das macht, was ich davon erwartete. Mein Programm funktionierte so nicht mehr, und ich wusste nicht, was ich falsch gemacht haben könnte.

Etwa einen halben Tag hat es gedauert, bis ich den Fehler gefunden hatte: java.awt.Toolkit.sync() verschluckt ganz frech das Interrupted-Flag. Es scheint leider wirklich so zu sein. Die Implementation der Java Virtual Machine von Oracle ist hier offenbar fehlerhaft, denn alles funktioniert einwandfrei wenn ich auf sync() verzichte. Sobald ich die Zeile verwende, klappt das Unterbrechen des Threads nicht mehr. Meine Vermutung ist daher, dass das blockierende sync() das Interrupted-Flag mittels interrupted() abfragt (und dadurch löscht!), und dann leider nicht mehr setzt und leider auch keine Exception wirft. Es verschluckt die Thread-Unterbrechung völlig. So wird dieser Mechanismus sogar ganz offiziell in der Java-Doku erklärt:

if (Thread.interrupted()) // Clears interrupted status!

Nun hält sich Oracle selbst nicht daran. Ich habe anschließend in meinem Code keine Möglichkeit mehr, diese Unterbrechung zu erkennen und gegebenenfalls selbst eine InterruptedException auszulösen. Oracle hat hier eindeutig Scheiße gebaut, denn eigentlich ist das Konsens, das Interrupted-Flag nach dem Löschen erneut zu setzen, damit die Unterbrechung nach oben eskaliert werden kann, so dass auch andere Programmteile auf die Unterbrechung korrekt reagieren können. Hier wurde ganz einfach geschlampt.

Und was macht sync() eigentlich? Tja, keine Ahnung. So ganz scheint das nämlich niemand zu wissen. Ich liebe es, wenn die Java-Dokumentation von Oracle so explizit ist, dass man trotzdem keine Ahnung hat, was genau vor sich geht. So auch zur Methode sync() der Klasse Toolkit:

void java.awt.Toolkit.sync()

Synchronizes this toolkit’s graphics state. Some window systems may do buffering of graphics events.

This method ensures that the display is up-to-date. It is useful for animation.

Wenn jemand mal im Internet in einschlägigen Entwicklerforen versucht danach zu fragen, was das genau bedeutet, wird die Frage mit „synchronizes the graphics state“ „beantwortet“, und anschließend als Off-Topic geschlossen. Zurecht wurde wenigstens noch darauf hingewiesen, dass das die Frage kaum beantwortet.

Da ich weder sagen kann, was die Methode macht, in welchen Fällen ich sie brauchen könnte, und welche Vorteile oder Nachteile damit zusammenhängen, werde ich auf sync() gerne verzichten, schon da ich mit dem Interrupt-Problem einen ziemlich schwerwiegenden Fehler entdeckt habe, den ich nicht bereit bin zu akzeptieren – ganz egal wie toll die Funktion ansonsten arbeiten möge.