Oechsle | Parallele und verteilte Anwendungen in Java | E-Book | sack.de
E-Book

E-Book, Deutsch, 472 Seiten

Oechsle Parallele und verteilte Anwendungen in Java


5. neu bearbeitete Auflage 2018
ISBN: 978-3-446-45603-7
Verlag: Hanser, Carl
Format: PDF
Kopierschutz: 1 - PDF Watermark

E-Book, Deutsch, 472 Seiten

ISBN: 978-3-446-45603-7
Verlag: Hanser, Carl
Format: PDF
Kopierschutz: 1 - PDF Watermark



Das Standardwerk zu Parallelität und VerteilungFür Nutzer ist es selbstverständlich, dass sie mehrere Programme gleichzeitig verwenden können oder dass Programme so komplex sind, dass sie auf mehrere Rechner zugreifen müssen. Aber wie werden solche Anwendungen programmiert?Das Lehrbuch behandelt zwei eng miteinander verknüpfte Basisthemen der Informatik: die Programmierung paralleler (nebenläufiger) und verteilter Anwendungen. Als Programmiersprache wird Java verwendet. Es werden zunächst anhand zahlreicher Beispiele grundlegende Synchronisationskonzepte für die Programmierung paralleler Abläufe präsentiert. Neben den "klassischen" Synchronisationsmechanismen von Java werden auch die Konzepte aus der Java-Concurrency-Klassenbibliothek vorgestellt. Weiteres Basiswissen, das zum Verständnis des Buchs notwendig ist, etwa über grafische Benutzeroberflächen, das MVC-Entwurfsmuster oder Rechnernetze, wird im Buch anschaulich und praxisnah vermittelt.Das Lehrbuch wendet sich an Studierende der Informatik und ingenieurwissenschaftlicher Studiengänge mit Grundkenntnissen in Java und Objektorientierung sowie Softwareentwickler. Die 5. Auflage wird aktualisiert und um neue Themen ergänzt.
Oechsle Parallele und verteilte Anwendungen in Java jetzt bestellen!

Autoren/Hrsg.


Weitere Infos & Material


1;Vorwort zur 5. Auflage;6
2;Inhalt;10
3;1 Einleitung;16
3.1;1.1 Parallelität, Nebenläufigkeit und Verteilung;16
3.2;1.2 Programme, Prozesse und Threads;17
4;2 Grundlegende Synchronisationskonzepte in Java;21
4.1;2.1 Erzeugung und Start von Java-Threads;21
4.1.1;2.1.1 Ableiten der Klasse Thread;21
4.1.2;2.1.2 Implementieren der Schnittstelle Runnable;23
4.1.3;2.1.3 Einige Beispiele;26
4.2;2.2 Probleme beim Zugriff auf gemeinsam genutzte Objekte;32
4.2.1;2.2.1 Erster Lösungsversuch;36
4.2.2;2.2.2 Zweiter Lösungsversuch;37
4.3;2.3 Synchronized und volatile;39
4.3.1;2.3.1 Synchronized-Methoden;39
4.3.2;2.3.2 Synchronized-Blöcke;40
4.3.3;2.3.3 Wirkung von synchronized;42
4.3.4;2.3.4 Notwendigkeit von synchronized;43
4.3.5;2.3.5 Volatile;44
4.3.6;2.3.6 Regel für die Nutzung von synchronized;45
4.4;2.4 Ende von Java-Threads;46
4.4.1;2.4.1 Asynchrone Beauftragung mit Abfragen der Ergebnisse;47
4.4.2;2.4.2 Zwangsweises Beenden von Threads;53
4.4.3;2.4.3 Asynchrone Beauftragung mit befristetem Warten;58
4.4.4;2.4.4 Asynchrone Beauftragung mit Rückruf (Callback);60
4.4.5;2.4.5 Asynchrone Beauftragung mit Rekursion;63
4.5;2.5 Wait und notify;66
4.5.1;2.5.1 Erster Lösungsversuch;67
4.5.2;2.5.2 Zweiter Lösungsversuch;68
4.5.3;2.5.3 Dritter Lösungsversuch;69
4.5.4;2.5.4 Korrekte und effiziente Lösung mit wait und notify;70
4.6;2.6 NotifyAll;78
4.6.1;2.6.1 Erzeuger-Verbraucher-Problem mit wait und notify;79
4.6.2;2.6.2 Erzeuger-Verbraucher-Problem mit wait und notifyAll;83
4.6.3;2.6.3 Faires Parkhaus mit wait und notifyAll;85
4.7;2.7 Prioritäten von Threads;87
4.8;2.8 Thread-Gruppen;94
4.9;2.9 Vordergrund- und Hintergrund-Threads;99
4.10;2.10 Weitere „gute“ und „schlechte“ Thread-Methoden;100
4.11;2.11 Thread-lokale Daten;102
4.12;2.12 Zusammenfassung;104
5;3 Fortgeschrittene Synchronisationskonzepte in Java;109
5.1;3.1 Semaphore;110
5.1.1;3.1.1 Einfache Semaphore;110
5.1.2;3.1.2 Einfache Semaphore für den gegenseitigen Ausschluss;111
5.1.3;3.1.3 Einfache Semaphore zur Herstellung vorgegebener Ausführungsreihenfolgen;113
5.1.4;3.1.4 Additive Semaphore;116
5.1.5;3.1.5 Semaphorgruppen;119
5.2;3.2 Message Queues;122
5.2.1;3.2.1 Verallgemeinerung des Erzeuger-Verbraucher-Problems;122
5.2.2;3.2.2 Übertragung des erweiterten Erzeuger-Verbraucher-Problems auf Message Queues;124
5.3;3.3 Pipes;127
5.4;3.4 Philosophen-Problem;130
5.4.1;3.4.1 Lösung mit synchronized – wait – notifyAll;131
5.4.2;3.4.2 Naive Lösung mit einfachen Semaphoren;133
5.4.3;3.4.3 Einschränkende Lösung mit gegenseitigem Ausschluss;135
5.4.4;3.4.4 Gute Lösung mit einfachen Semaphoren;136
5.4.5;3.4.5 Lösung mit Semaphorgruppen;139
5.5;3.5 Leser-Schreiber-Problem;141
5.5.1;3.5.1 Lösung mit synchronized – wait – notifyAll;142
5.5.2;3.5.2 Lösung mit additiven Semaphoren;146
5.6;3.6 Schablonen zur Nutzung der Synchronisationsprimitive und Konsistenzbetrachtungen;147
5.7;3.7 Concurrent-Klassenbibliothek aus Java 5;151
5.7.1;3.7.1 Executors;152
5.7.2;3.7.2 Locks und Conditions;158
5.7.3;3.7.3 Atomic-Klassen;166
5.7.4;3.7.4 Synchronisationsklassen;170
5.7.5;3.7.5 Queues;173
5.8;3.8 Das Fork-Join-Framework von Java 7;174
5.8.1;3.8.1 Grenzen von ThreadPoolExecutor;174
5.8.2;3.8.2 ForkJoinPool und RecursiveTask;176
5.8.3;3.8.3 Beispiel zur Nutzung des Fork-Join-Frameworks;178
5.9;3.9 Das Data-Streaming-Framework von Java 8;181
5.9.1;3.9.1 Einleitendes Beispiel;181
5.9.2;3.9.2 Sequenzielles Data-Streaming;183
5.9.3;3.9.3 Paralleles Data-Streaming;187
5.10;3.10 Die Completable Futures von Java 8;188
5.11;3.11 Ursachen für Verklemmungen;195
5.11.1;3.11.1 Beispiele für Verklemmungen mit synchronized;196
5.11.2;3.11.2 Beispiele für Verklemmungen mit Semaphoren;199
5.11.3;3.11.3 Bedingungen für das Eintreten von Verklemmungen;200
5.12;3.12 Vermeidung von Verklemmungen;201
5.12.1;3.12.1 Anforderung von Betriebsmitteln „auf einen Schlag“;204
5.12.2;3.12.2 Anforderung von Betriebsmitteln gemäß einer vorgegebenen Ordnung;205
5.12.3;3.12.3 Weitere Verfahren;206
5.13;3.13 Zusammenfassung;208
6;4 Parallelität und grafische Benutzeroberflächen;210
6.1;4.1 Einführung in die Programmierung grafischer Benutzeroberflächen mit JavaFX;211
6.1.1;4.1.1 Allgemeines zu grafischen Benutzeroberflächen;211
6.1.2;4.1.2 Erstes JavaFX-Beispiel;212
6.1.3;4.1.3 Ereignisbehandlung;213
6.2;4.2 Properties, Bindings und JavaFX-Collections;217
6.2.1;4.2.1 Properties;217
6.2.2;4.2.2 Bindings;220
6.2.3;4.2.3 JavaFX-Collections;222
6.3;4.3 Elemente von JavaFX;222
6.3.1;4.3.1 Container;222
6.3.2;4.3.2 Interaktionselemente;225
6.3.3;4.3.3 Grafikprogrammierung;227
6.3.4;4.3.4 Weitere Funktionen von JavaFX;233
6.4;4.4 MVP;234
6.4.1;4.4.1 Prinzip von MVP;235
6.4.2;4.4.2 Beispiel zu MVP;236
6.5;4.5 Threads und JavaFX;243
6.5.1;4.5.1 Threads für JavaFX;243
6.5.2;4.5.2 Länger dauernde Ereignisbehandlungen;244
6.5.3;4.5.3 Beispiel Stoppuhr;249
6.5.4;4.5.4 Tasks und Services in JavaFX;255
6.6;4.6 Zusammenfassung;264
7;5 Verteilte Anwendungen mit Sockets;265
7.1;5.1 Einführung in das Themengebiet der Rechnernetze;266
7.1.1;5.1.1 Schichtenmodell;266
7.1.2;5.1.2 IP-Adressen und DNS-Namen;270
7.1.3;5.1.3 Das Transportprotokoll UDP;271
7.1.4;5.1.4 Das Transportprotokoll TCP;272
7.2;5.2 Socket-Schnittstelle;273
7.2.1;5.2.1 Socket-Schnittstelle zu UDP;273
7.2.2;5.2.2 Socket-Schnittstelle zu TCP;275
7.2.3;5.2.3 Socket-Schnittstelle für Java;277
7.3;5.3 Kommunikation über UDP mit Java-Sockets;278
7.4;5.4 Multicast-Kommunikation mit Java-Sockets;287
7.5;5.5 Kommunikation über TCP mit Java-Sockets;291
7.6;5.6 Sequenzielle und parallele Server;301
7.6.1;5.6.1 TCP-Server mit dynamischer Parallelität;302
7.6.2;5.6.2 TCP-Server mit statischer Parallelität;306
7.6.3;5.6.3 Sequenzieller, „verzahnt“ arbeitender TCP-Server;311
7.7;5.7 Zusammenfassung;315
8;6 Verteilte Anwendungen mit RMI;316
8.1;6.1 Prinzip von RMI;316
8.2;6.2 Einführendes RMI-Beispiel;319
8.2.1;6.2.1 Basisprogramm;319
8.2.2;6.2.2 RMI-Client mit grafischer Benutzeroberfläche;323
8.2.3;6.2.3 RMI-Registry;328
8.3;6.3 Parallelität bei RMI-Methodenaufrufen;332
8.4;6.4 Wertübergabe für Parameter und Rückgabewerte;336
8.4.1;6.4.1 Serialisierung und Deserialisierung von Objekten;337
8.4.2;6.4.2 Serialisierung und Deserialisierung bei RMI;342
8.5;6.5 Referenzübergabe für Parameter und Rückgabewerte;346
8.6;6.6 Transformation lokaler in verteilte Anwendungen;361
8.6.1;6.6.1 Rechnergrenzen überschreitende Synchronisation mit RMI;361
8.6.2;6.6.2 Asynchrone Kommunikation mit RMI;364
8.6.3;6.6.3 Verteilte MVP-Anwendungen mit RMI;365
8.7;6.7 Dynamisches Umschalten zwischen Wert- und Referenzübergabe – Migration von Objekten;366
8.7.1;6.7.1 Das Exportieren und „Unexportieren“ von Objekten;366
8.7.2;6.7.2 Migration von Objekten;369
8.7.3;6.7.3 Eintrag eines Nicht-Stub-Objekts in die RMI-Registry;376
8.8;6.8 Laden von Klassen über das Netz;377
8.9;6.9 Realisierung von Stubs und Skeletons;378
8.9.1;6.9.1 Realisierung von Skeletons;379
8.9.2;6.9.2 Realisierung von Stubs;379
8.10;6.10 Verschiedenes;382
8.11;6.11 Zusammenfassung;383
9;7 Webbasierte Anwendungen mit Servlets und JSF;384
9.1;7.1 HTTP und HTML;385
9.1.1;7.1.1 GET;385
9.1.2;7.1.2 Formulare in HTML;388
9.1.3;7.1.3 POST;390
9.1.4;7.1.4 Format von HTTP-Anfragen und -Antworten;391
9.2;7.2 Einführende Servlet-Beispiele;392
9.2.1;7.2.1 Allgemeine Vorgehensweise;392
9.2.2;7.2.2 Erstes Servlet-Beispiel;393
9.2.3;7.2.3 Zugriff auf Formulardaten;395
9.2.4;7.2.4 Zugriff auf die Daten der HTTP-Anfrage und -Antwort;397
9.3;7.3 Parallelität bei Servlets;398
9.3.1;7.3.1 Demonstration der Parallelität von Servlets;398
9.3.2;7.3.2 Paralleler Zugriff auf Daten;400
9.3.3;7.3.3 Anwendungsglobale Daten;404
9.4;7.4 Sessions und Cookies;407
9.4.1;7.4.1 Sessions;408
9.4.2;7.4.2 Realisierung von Sessions mit Cookies;412
9.4.3;7.4.3 Direkter Zugriff auf Cookies;414
9.4.4;7.4.4 Servlets mit länger dauernden Aufträgen;415
9.5;7.5 Asynchrone Servlets;421
9.6;7.6 Filter;425
9.7;7.7 Übertragung von Dateien mit Servlets;426
9.7.1;7.7.1 Herunterladen von Dateien;426
9.7.2;7.7.2 Hochladen von Dateien;429
9.8;7.8 JSF (Java Server Faces);432
9.8.1;7.8.1 Einführendes Beispiel;432
9.8.2;7.8.2 Managed Beans und deren Scopes;439
9.8.3;7.8.3 MVP-Prinzip mit JSF;443
9.8.4;7.8.4 AJAX mit JSF;444
9.9;7.9 RESTful WebServices;448
9.9.1;7.9.1 Definition von RESTful WebServices;449
9.9.2;7.9.2 JSON;450
9.9.3;7.9.3 Beispiel;452
9.10;7.10 WebSockets;457
9.11;7.11 Zusammenfassung;461
10;Literatur;464
11;Index;466


1 Einleitung

Computer-Nutzer dürften mit großer Wahrscheinlichkeit sowohl mit parallelen Abläufen auf ihrem eigenen Rechner als auch verteilten Anwendungen vertraut sein. So ist jeder Benutzer eines PC heutzutage gewohnt, dass z. B. gleichzeitig eine größere Video-Datei kopiert, ein Musikstück aus einer MP3-Datei abgespielt, ein Java-Programm übersetzt und ein Dokument in einem Editor oder Textverarbeitungsprogramm bearbeitet werden kann. Aufgrund der Tatsache, dass die Mehrzahl der genutzten Computer an das Internet angeschlossen ist, sind heute auch nahezu alle den Umgang mit verteilten Anwendungen wie der elektronischen Post oder dem World Wide Web gewohnt.

Dieses Buch handelt allerdings nicht von der Benutzung, sondern von der Entwicklung paralleler und verteilter Anwendungen mit Java. In diesem ersten einleitenden Kapitel werden zunächst einige wichtige Begriffe wie Parallelität, Nebenläufigkeit, Verteilung, Prozesse und Threads geklärt.

1.1 Parallelität, Nebenläufigkeit und Verteilung

Wenn mehrere Vorgänge gleichzeitig auf einem Rechner ablaufen, so sprechen wir von Parallelität oder Nebenläufigkeit (engl. concurrency). Diese Vorgänge können dabei echt gleichzeitig oder nur scheinbar gleichzeitig ablaufen: Wenn ein Rechner mehrere Prozessoren bzw. einen Mehrkernprozessor (Multicore-Prozessor) besitzt, dann ist echte Gleichzeitigkeit möglich. Man spricht in diesem Fall auch von echter Parallelität. Besitzt der Rechner aber nur einen einzigen Prozessor mit einem einzigen Kern, so wird die Gleichzeitigkeit der Abläufe nur vorgetäuscht, indem in sehr hoher Frequenz von einem Vorgang auf den nächsten umgeschaltet wird. Man spricht in diesem Fall von Pseudoparallelität oder Nebenläufigkeit. Die Begriffe Parallelität und Nebenläufigkeit werden in der Literatur nicht einheitlich verwendet: Einige Autoren verwenden den Begriff Nebenläufigkeit als Oberbegriff für echte Parallelität und Pseudoparallelität, für andere Autoren sind Nebenläufigkeit und Pseudoparallelität Synonyme. In diesem Buch wird der Einfachheit halber nicht zwischen Nebenläufigkeit und Parallelität unterschieden; mit beiden Begriffen sollen sowohl die echte als auch die Pseudoparallelität gemeint sein.

Wenn das gleichzeitige Ablaufen von Vorgängen auf mehreren Rechnern betrachtet wird, wobei die Rechner über ein Rechnernetz gekoppelt sind und darüber miteinander kommunizieren, spricht man von Verteilung (verteilte Systeme, verteilte Anwendungen).

Wir unterscheiden also, ob die Vorgänge auf einem Rechner oder auf mehreren Rechnern gleichzeitig ablaufen; im ersten Fall sprechen wir von Parallelität, im anderen Fall von Verteilung. Die Mehrzahl der Leserinnen und Leser dürfte vermutlich mit dieser Unterscheidung zufrieden sein. In manchen Fällen ist es aber gar nicht so einfach zu entscheiden, ob ein gegebenes System einen einzigen Rechner oder eine Vielzahl von Rechnern darstellt. Betrachten Sie z. B. ein System zur Steuerung von Maschinen, wobei dieses System in einem Schaltschrank untergebracht ist, in dem sich mehrere Einschübe mit Prozessoren befinden. Handelt es sich hier um einen oder um mehrere kommunizierende Rechner? Zur Klärung dieser Frage wollen wir uns hier an die allgemein übliche Unterscheidung zwischen eng und lose gekoppelten Systemen halten: Ein eng gekoppeltes System ist ein Rechnersystem bestehend aus mehreren gekoppelten Prozessoren, wobei diese auf einen gemeinsamen Speicher (Hauptspeicher) zugreifen können. Ein lose gekoppeltes System (auch verteiltes System genannt) besteht aus mehreren gekoppelten Prozessoren ohne gemeinsamen Speicher (Hauptspeicher), die über ein Kommunikationssystem Nachrichten austauschen. Ein eng gekoppeltes System sehen wir als einen einzigen Rechner, während wir ein lose gekoppeltes System als einen Verbund mehrerer Rechner betrachten.

Parallelität und Verteilung schließen sich nicht gegenseitig aus, sondern hängen im Gegenteil eng miteinander zusammen: In einem verteilten System laufen auf jedem einzelnen Rechner mehrere Vorgänge parallel (echt parallel oder pseudoparallel) ab. Wie auch in diesem Buch noch ausführlich diskutiert wird, arbeitet ein Server im Rahmen eines Client-Server-Szenarios häufig parallel, um mehrere Clients gleichzeitig zu bedienen. Außerdem können verteilte Anwendungen, die für den Ablauf auf unterschiedlichen Rechnern vorgesehen sind, im Spezialfall auf einem einzigen Rechner parallel ausgeführt werden.

Sowohl Parallelität als auch Verteilung werden durch Hard- und Software realisiert. Bei der Software spielt das Betriebssystem eine entscheidende Rolle. Das Betriebssystem verteilt u. a. die auf einem Rechner gleichzeitig möglichen Abläufe auf die vorhandenen Prozessoren bzw. die vorhandenen Kerne des Rechners. Auf diese Art vervielfacht also das Betriebssystem die Anzahl der vorhandenen Prozessoren bzw. der vorhandenen Kerne virtuell. Diese Virtualisierung ist eines der wichtigen Prinzipien von Betriebssystemen, die auch für andere Ressourcen realisiert wird. So wird z. B. durch das Konzept des virtuellen Speichers ein größerer Hauptspeicher vorgegaukelt als tatsächlich vorhanden. Erreicht wird dies, indem immer die gerade benötigten Daten vom Hintergrundspeicher (Platte) in den Hauptspeicher transferiert werden.

1.2 Programme, Prozesse und Threads

Im Zusammenhang mit Parallelität bzw. Nebenläufigkeit und Verteilung muss zwischen den Begriffen Programm, Prozess und Thread (Ausführungsfaden) unterschieden werden. Da es einen engen Zusammenhang zu den Themen Betriebssysteme, Rechner und verteilte Systeme gibt, sollen alle diese Begriffe anhand einer Metapher verdeutlicht werden:

  • Ein Programm entspricht einem Rezept in einem Kochbuch. Es ist statisch. Es hat keine Wirkung, solange es nicht ausgeführt wird. Dass man von einem Rezept nicht satt wird, ist hinlänglich bekannt.

  • Einen Prozess kann man sich vorstellen als eine Küche und einen Thread als einen Koch. Ein Koch kann nur in einer Küche existieren, aber nie außerhalb davon. Umgekehrt muss sich in einer Küche immer mindestens ein Koch befinden. Alle Köche gehen streng nach Rezepten vor, wobei unterschiedliche Köche nach demselben oder nach unterschiedlichen Rezepten kochen können. Jede Küche hat ihre eigenen Pfannen, Schüsseln, Herde, Waschbecken, Messer, Gewürze, Lebensmittel usw. Köche in unterschiedlichen Küchen können sich gegenseitig nicht in die Quere kommen, wohl aber die Köche in einer Küche. Diese müssen den Zugriff auf die Materialien und Geräte der Küche koordinieren.

  • Ein Rechner ist in dieser Metapher ein Haus, in dem sich mehrere Küchen befinden.

  • Ein Betriebssystem lässt sich mit einem Hausmeister eines Hauses vergleichen, der dafür sorgt, dass alles funktioniert (z. B. dass immer Strom für den Herd da ist). Der Hausmeister übernimmt u. a. auch die Rolle eines Boten zwischen den Küchen, um Gegenstände oder Informationen zwischen den Küchen auszutauschen. Auch kann er eine Küche durch einen Anbau vergrößern, wenn eine Küche zu klein geworden ist.

Ein verteiltes System besteht entsprechend aus mehreren solcher Häuser mit Küchen, wobei die Hausmeister der einzelnen Häuser z. B. über Telefon oder über hin- und herlaufende Boten untereinander kommunizieren können. Somit können Köche, die in unterschiedlichen Häusern arbeiten, Gegenstände oder Informationen austauschen, indem sie ihre jeweiligen Hausmeister damit beauftragen.

Diese Begriffe und ihre Beziehung sind in Bild 1.1 zusammenfassend dargestellt.

Bild 1.1 Häuser, Küchen, Köche und Hausmeister als Metapher für Rechner, Prozesse, Threads und Betriebssysteme

Am Beispiel der Programmiersprache Java und der Ausführung von Java-Programmen lässt sich diese Metapher nun auf die Welt der Informatik übertragen:

  • Ein Programm (Kochrezept) ist in einer Datei abgelegt: als Quelltext in einer oder mehreren Java-Dateien und als übersetztes Programm (Byte-Code) in einer oder mehreren Class-Dateien.

  • Zum Ausführen eines Programms mit Hilfe des Kommandos java wird eine JVM (Java Virtual Machine) gestartet. Bei jedem Erteilen des Java-Kommandos wird ein neuer Prozess (Küche) erzeugt. Ein Prozess stellt im Wesentlichen einen Adressraum für den Programmcode und die Daten dar. Der Programmcode, der sich in einer oder mehreren Dateien befindet, wird in den Adressraum des Prozesses geladen. Es ist möglich, mehrere JVMs zu starten, so dass die entsprechenden Prozesse alle gleichzeitig existieren, wobei jeder Prozess seinen eigenen Adressraum besitzt.

  • Jeder Prozess und damit auch jede JVM hat als Aktivitätsträger mindestens einen Thread (Koch). Neben den so genannten Hintergrund-Threads, die z. B. für die Speicherbereinigung (Garbage...


Prof. Dr. Rainer Oechsle ist Professor für Rechnernetze und Verteilte Systeme im Fachbereich Informatik an der Hochschule Trier.



Ihre Fragen, Wünsche oder Anmerkungen
Vorname*
Nachname*
Ihre E-Mail-Adresse*
Kundennr.
Ihre Nachricht*
Lediglich mit * gekennzeichnete Felder sind Pflichtfelder.
Wenn Sie die im Kontaktformular eingegebenen Daten durch Klick auf den nachfolgenden Button übersenden, erklären Sie sich damit einverstanden, dass wir Ihr Angaben für die Beantwortung Ihrer Anfrage verwenden. Selbstverständlich werden Ihre Daten vertraulich behandelt und nicht an Dritte weitergegeben. Sie können der Verwendung Ihrer Daten jederzeit widersprechen. Das Datenhandling bei Sack Fachmedien erklären wir Ihnen in unserer Datenschutzerklärung.