Ist meine static Helper Class Thread save?

Thallius

Top Contributor
Hi,

ich habe mir eine kleine Klasse geschrieben, die debug informationen in eine Datei schreibt. Diese habe ich statisch gemacht um einfacher von allen anderen Klassen darauf zugreifen zu können. Ich bin jetzt aber nicht sicher, ob diese wirklich Thread safe ist, da sie von vielen Threads gleichzeitig aufgerufen werden kann.
Eigentlich sollte sie das sein da sie nur lokale Variablen (Stackvariablen) ändert. Aber was passiert, wenn die write Methode von mehreren Threads gleichzeitig aufgerunfen wird? Kann es dann zu Problemen kommen ?

Code:
public final class Logger
{
    private static String filename = null;
    private static boolean verbose;

    /**
     * Init logging by creating file for actual day
     *
     * @param verb If true, all logger outputs are also streamed to the console.
     * @return True on success, false on error
     */
    public static boolean init(boolean verb)
    {
        verbose = verb;

        String filePath = GlobalSettings.getPathForFile("logs");
        if(filePath == null)
            return false;

        File directory = new File(filePath);
        if (!directory.exists())
        {
            if(!directory.mkdir())
                return false;

        }
        filename = GlobalSettings.getPathForFile("logs"+File.separator+ Util.sqlDateFromLocalDate(LocalDate.now())+".txt");

        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        filename = filePath+File.separator+today+".txt";
        return true;
    }

    /**
     * Write text to log
     *
     * @param string Text to write
     */
    public static void log(String string)
    {
        Logger.write(string);
    }

    /**
     * Write double to log
     *
     * @param value Double value to write to log
     */
    @SuppressWarnings("unused")
    public static void log(double value)
    {
        Logger.write(String.format("%f", value)); //$NON-NLS-1$
    }

    /**
     * Write object to log
     *
     * @param object Object to write to log
     */
    public static void log(Object object)
    {
        Logger.write(object.toString());
    }

    /**
     * Write to log
     *
     * @param string Text to write
     */
    private static void write(String string)
    {
        try
        {
            DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); //$NON-NLS-1$
            Calendar cal = Calendar.getInstance();
            string=dateFormat.format(cal.getTime())+" "+string; //$NON-NLS-1$
            FileWriter fw = new FileWriter(filename,true);
            fw.write(string+System.getProperty("line.separator")); //$NON-NLS-1$
            fw.close();
            if(verbose)
                System.out.println(string);
        }
        catch(IOException ioe)
        {
            System.err.println("IOException: " + ioe.getMessage()); //$NON-NLS-1$
        }
    }
}
 

LimDul

Top Contributor
Mit ziemlicher Sicherheit nein.

Folgender Block alleine:
Java:
 FileWriter fw = new FileWriter(filename,true);
            fw.write(string+System.getProperty("line.separator")); //$NON-NLS-1$
Was ist, wenn zwei oder mehrere Filewriter gleichzeitig geöffnet werden? Ich glaube nicht, dass das gut geht.

Und wenn ich typische Logging Szenarien denke, halte ich es für extrem viel Overhead jedes mal die Datei auf & zu zu machen.

Außerdem wäre ein ty-with-resources sinnvoll - im Falle einer Exception wird der Filewriter nicht geschlossen.
 

LimDul

Top Contributor
Noch ein paar Nachträge, die mir eingefallen sind:
- Die Init Methode ist auch nicht Thread-Safe, die kann mit false abbrechen wenn zwei Threads parallel abarbeiten (Verzeichnis ist nicht da - beide Threads versuchen es anzulegen, nur einer gewinnt)
- Warum nutzt du nicht bestehende Logging Frameworks wie z.B. SL4J mit logback?
- An die Log Methode wird normalerweise die Anforderung gestellt, dass sie extrem schnell wieder zurückkommen soll. Das aufmachen eines Filewriters inkl. Schreiben in eine Datei dürfte so ziemlich das Gegenteil von extrem schnell sein. Ich weiß nicht wie Logging Frameworks das machen - aber wenn ich einen Logger schreiben würde, der Daten in externe Resourcen wie Dateien oder Netzwerk schiebt muss das möglichst robust sein ohne die eigentliche Anwendung zu belasten. Sprich, ich würde das wegschreiben ihn einen eigenen Thread auslagern und den Logger die Daten an den anderen Thread übergeben lasse über eine "klassische" Queue die entsprechend Multi-Threading fähig. Der Thread zum protokollieren in die Datei sollte dann sinnvollerweise auch möglichst failsafe sein und ggf. versuchen es noch mal wegzuschreiben bei IO-Exceptions. Ein Logging Framework, was Log Messages verliert weil gerade mal eine IO Resource "Schluckauf" hat, ist kein gutes Logging Framework.

Musst halt für dich entscheiden, wie viel du davon umsetzen willst.
 

Thallius

Top Contributor
Die Init Methode wird ja nicht von jedem Thread aufgerufen sondern nur einmal beim Start der App.

Geschwindigkeit ist hier auch kein thema da nur Fehler geloggt werden, von denen es hoffentlich nicht viele gibt :)

Ein dickes Framework dafür reinzusetzen widerstrebt mir eben
 

Blender3D

Top Contributor
Aber was passiert, wenn die write Methode von mehreren Threads gleichzeitig aufgerunfen wird? Kann es dann zu Problemen kommen ?
Ich denke ja.
Die Strings in einen Buffer geben und von einem Thread das Schreiben ausführen lassen. --> Nur der Logger schreibt in die Datei. Die Aufrufer schreiben in den Buffer.
Habe eine Codevorschlag. Ist nicht getestet. Vielleicht kannst Du daraus etwas machen.
Java:
public final class Logger {
    private volatile static AtomicBoolean busy = new AtomicBoolean(false); // true -> writing is not done yet
    private static String filename = null;
    private static boolean verbose;
    private static volatile ConcurrentLinkedQueue<String> buffer = new ConcurrentLinkedQueue<String>();
    private static boolean running;
    protected static volatile Thread logThread = createLogWriterThread();

    private static Thread createLogWriterThread() {
        running = true;
        return new Thread(new Runnable() {
            @Override
            public void run() {
                while (running) {
                    try {
                        if (!buffer.isEmpty())
                            write();
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    /**
     * Init logging by creating file for actual day
     *
     * @param verb
     *            If true, all logger outputs are also streamed to the console.
     * @return True on success, false on error
     */
    public static boolean init(boolean verb) {
        verbose = verb;

        String filePath = GlobalSettings.getPathForFile("logs");
        if (filePath == null)
            return false;

        File directory = new File(filePath);
        if (!directory.exists()) {
            if (!directory.mkdir())
                return false;
        }
        // 1) assignment to filename
        filename = GlobalSettings
                .getPathForFile("logs" + File.separator + Util.sqlDateFromLocalDate(LocalDate.now()) + ".txt");

        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        // 2) assignment to filename but not used till now ??
        filename = filePath + File.separator + today + ".txt";
        start();
        return true;
    }

    /**
     * Write text to log
     *
     * @param string
     *            Text to write
     */
    public static void log(String string) {
        Logger.write(string);
    }

    /**
     * Write double to log
     *
     * @param value
     *            Double value to write to log
     */
    @SuppressWarnings("unused")
    public static void log(double value) {
        Logger.write(String.format("%f", value)); //$NON-NLS-1$
    }

    /**
     * Write object to log
     *
     * @param object
     *            Object to write to log
     */
    public static void log(Object object) {
        Logger.write(object.toString());
    }

    private static void start() {
        if (logThread != null && logThread.isAlive())
            return;
        logThread = createLogWriterThread();
        logThread.start();
    }

    public static void stopLogger() {
        running = false;
        logThread = null;
    }

    private static void write(String string) {
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss"); //$NON-NLS-1$
        Calendar cal = Calendar.getInstance();
        string = dateFormat.format(cal.getTime()) + " " + string; //$NON-NLS-1$
        buffer.offer(string);
    }

    /**
     * Tries to write log with feedback.
     *
     * @param string
     *            Text to write
     * @return true if successful.
     */
    private static void write() {
        if (busy.get())
            return;
        busy.set(true);
        PrintWriter out = null;
        try {
            while (!buffer.isEmpty()) {
                String string = buffer.poll();
                out = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)));
                out.write(string + System.getProperty("line.separator")); //$NON-NLS-1$
                out.close();
                if (verbose)
                    System.out.println(string);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } finally { // ensure that file will be closed
            if (out != null)
                out.close();
            busy.set(false);
        }
    }
}
 

Blender3D

Top Contributor
Java:
      out = new PrintWriter(new BufferedWriter(new FileWriter(filename, true)));
      while (!buffer.isEmpty()) {
                String string = buffer.poll();               
                out.write(string + System.getProperty("line.separator")); //$NON-NLS-1$               
                if (verbose)
                    System.out.println(string);
            }
Writer erzeugen muss noch aus der Schleife raus
 

Thallius

Top Contributor
Das einzige was mich daran stört ist das polling. Aber Java stellt glaube ich sonst keine Bordmittel zur Verfügung um messaging zu machen
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Tobero Meine Funktion für das beinhalten eines Punktes in einem Kreis funktioniert nicht Allgemeine Java-Themen 5
T Meine Frage lautet wie ich 2 CSV Dateien miteinander in Java verbinde und Spalten die zueinander gehören durch den gleichen Key zusammen ausgebe? Allgemeine Java-Themen 5
X Wie kann ich meine Stdlib in Intelliji benutzen? Allgemeine Java-Themen 3
B Wie kann ich meine Pläne am besten umsetzen? Allgemeine Java-Themen 2
B Suche nach einem Testprogramm für meine BA Allgemeine Java-Themen 0
Thallius Warum ist meine private porperty public? Allgemeine Java-Themen 7
V Threads Weshalb funktionieren meine Threads nicht? Allgemeine Java-Themen 2
A Eine Spezifikation für meine Bachelorarbeit! Allgemeine Java-Themen 3
B Schnittstelle von Facebook zu Java(Eclipse) für meine Internetseite Allgemeine Java-Themen 20
S import meine.eigenes.import Allgemeine Java-Themen 6
Luk10 Factory auf meine Situaion anwendbar? Allgemeine Java-Themen 14
S HTML => DOM - Welcher Parser für meine Zwecke? Allgemeine Java-Themen 3
S ThreadPoolExecutor: wie stelle ich fest dass meine Threads im Pool mit ihrer Arbeit fertig sind? Allgemeine Java-Themen 3
D Ich möchte meine *.java Dateien in Applets "umschreiben. Aber wie? Allgemeine Java-Themen 3
V Math.log auf meine Art zu ungenau Allgemeine Java-Themen 15
B log4j löscht meine Logdateien Allgemeine Java-Themen 2
E JFreeChart jars mit in meine Jar packen Allgemeine Java-Themen 6
T NetBeans: Ist meine Konfiguration falsch? Allgemeine Java-Themen 7
M Windows: Start --> Ausführen --> [url]http://meine.url.com[/url] Allgemeine Java-Themen 3
J Was ist genauer: Thread.sleep() oder meine Variante? Allgemeine Java-Themen 64
E Was ist ein gutes Design fuer meine Programm? Allgemeine Java-Themen 3
S Ich verstehe meine Java-Version nicht Allgemeine Java-Themen 6
P meine selectAll methode makiert text nicht? Allgemeine Java-Themen 9
S Paar Infos für meine Dokumentation. Allgemeine Java-Themen 5
H Java mag meine Klasse nicht, Identifier expected Allgemeine Java-Themen 6
T Soll ich meine Software als freeware zum download geben? Allgemeine Java-Themen 15
D Laufen meine alten progs auf java 5 noch? Allgemeine Java-Themen 7
P Welches JRE braucht meine Applikation? Allgemeine Java-Themen 3
B Meine Hausaufgaben... Allgemeine Java-Themen 14
S meine java laufschrift funzt auf meinem NB teilweise schrott Allgemeine Java-Themen 2
E Methoden abstract static Methode Allgemeine Java-Themen 8
N nicht static und auch nicht new Allgemeine Java-Themen 3
P static Blocks und variablen Allgemeine Java-Themen 41
Kirby.exe Cannot make a static reference to the non-static field rimWidth Allgemeine Java-Themen 12
S static in Interface und Klasse Allgemeine Java-Themen 2
S static methode im Interface Allgemeine Java-Themen 1
A Variablen non-static variable cannot be referenced from a static content Allgemeine Java-Themen 4
P Static Variable -> unterschiedliche Werte? Allgemeine Java-Themen 1
K Static Variablen verbieten Allgemeine Java-Themen 10
C Generic collections und static typing Allgemeine Java-Themen 4
M Warum nicht static ? Allgemeine Java-Themen 10
M Eine static-Methode verlassen Allgemeine Java-Themen 2
B Schlüsselworte [ERLEDIGT] static { } - Was ist das und wofür kann ich das brauchen? Allgemeine Java-Themen 1
J private static final String variable Allgemeine Java-Themen 8
L Non-static-Variables in Enumerationen Allgemeine Java-Themen 2
L OOP Klassen-Design (static oder nicht?) Allgemeine Java-Themen 3
T Enumeration/Static Final/Bitfield Allgemeine Java-Themen 6
T Static kann nicht verändert werden Allgemeine Java-Themen 3
W Threads Cannot make a static reference.. Allgemeine Java-Themen 13
H Programierstil: static - Zugriff vs. Staticzugriff Allgemeine Java-Themen 24
N Static oder andere Lösung Allgemeine Java-Themen 5
N Vererbung Static & private fields - Nicht ganz einfach? Allgemeine Java-Themen 4
M Wo hin mit static factory methods? Allgemeine Java-Themen 40
M Public Static importRunning -> Bad Design oder ok ? Allgemeine Java-Themen 5
S Cannot make a static reference to the non-static field MySecondClass.Points Allgemeine Java-Themen 3
M Methoden Static Methoden und Thread??? Allgemeine Java-Themen 4
S auf public void Methode zugreifen ohne static Allgemeine Java-Themen 11
K Static - Problem Allgemeine Java-Themen 10
M Variablen Variablenzugriff aus static void Allgemeine Java-Themen 21
D API - Beispiel + static member in inner (non static) class Allgemeine Java-Themen 2
S static methoden Allgemeine Java-Themen 9
S Performance Frage: Objekt oder static? Allgemeine Java-Themen 33
X HTTP Problem mit static/non static JTextArea Update Allgemeine Java-Themen 17
A Annotation einer Subklasse im static-Block auslesen. Allgemeine Java-Themen 6
woezelmann referenz der outer class aus static nested class heraus Allgemeine Java-Themen 7
B static Variable / Unterklasse Allgemeine Java-Themen 2
I Was macht static { ... } ? Allgemeine Java-Themen 8
G static inner Klassen Allgemeine Java-Themen 7
G static und dynamic linking? Allgemeine Java-Themen 32
J in einer static Variable Wert ändern Allgemeine Java-Themen 6
J Verständnisfrage - nested static classes Allgemeine Java-Themen 11
G static- Methoden überschreiben Allgemeine Java-Themen 10
E Geschwindigkeit static Allgemeine Java-Themen 6
V Static oder wie? Allgemeine Java-Themen 61
I reflection get inner static classes Allgemeine Java-Themen 2
L static main - Spezifikation? Allgemeine Java-Themen 7
G URLClassLoader stößt static Block nicht an Allgemeine Java-Themen 8
D static Allgemeine Java-Themen 46
P static-Methode aus dem Konstruktor aufrufen Allgemeine Java-Themen 6
oliver1974 "(.) should be accessed in a static way" Falsche W Allgemeine Java-Themen 6
P static Klassenvariable Allgemeine Java-Themen 15
B JPasswordField klassenübergreifend auslesen->static Probl Allgemeine Java-Themen 4
F Methoden: static vs. instance Allgemeine Java-Themen 24
MQue static Methoden/Klassen Allgemeine Java-Themen 7
K Warum static-Methoden nutzen Allgemeine Java-Themen 26
G Java-Befehle Native und Static Allgemeine Java-Themen 2
conan2 static-Block in Klassen Allgemeine Java-Themen 6
M JNI, static.a mit load.Library laden? Allgemeine Java-Themen 2
K Static Members von Superklasse für JEDEN Erben Allgemeine Java-Themen 6
padde479 The static method sleep(long) from the type Thread should. Allgemeine Java-Themen 2
M static-Methode vorschreiben Allgemeine Java-Themen 5
S singleton vs. static Allgemeine Java-Themen 7
G Object mit static Feldern speichern Allgemeine Java-Themen 9
J Warum heißt es eig. "public static void main" ? Allgemeine Java-Themen 4
conan2 "Cannot make a static reference to the non-static field Allgemeine Java-Themen 8
P Singleton vs static Allgemeine Java-Themen 19
J parameterized und static fields Allgemeine Java-Themen 4
A Static reference to non-static field Allgemeine Java-Themen 10
S static umgehen Allgemeine Java-Themen 5
G static oder nicht Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben