Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在静态类中同步文件输出_Java_Multithreading - Fatal编程技术网

Java 在静态类中同步文件输出

Java 在静态类中同步文件输出,java,multithreading,Java,Multithreading,我有几个线程需要写入两个不同的文本文件。到目前为止,我有以下代码: public class Logger { public static void printToGameLog(String value){ Writer writer = null; try { writer = new BufferedWriter(new OutputStreamWriter( new FileOutputSt

我有几个线程需要写入两个不同的文本文件。到目前为止,我有以下代码:

public class Logger {

    public static void printToGameLog(String value){
        Writer writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("GameLog.txt", true), "utf-8"));
            synchronized(writer){
                writer.write(outputString + "\r\n");
            }
        } catch (IOException ex){
            System.out.println("cannot create log file");
        } 
    }


    public static void printToServerLog(String value){
        Writer writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("serverLog.txt", true), "utf-8"));
            synchronized(writer){
                writer.write(outputString + "\r\n");
            }
        } catch (IOException ex){
            System.out.println("cannot create log file");
        }
    }
}
这是一种可接受的方法,可以确保在同一时间不超过一个线程写入同一文件吗


如果一个线程调用其中一个方法并进入同步块,那么如果另一个线程出现并尝试执行同一个方法,会发生什么情况。当它尝试使用局部变量
writer
时,是否会尝试获取已被另一个线程锁定并因此阻塞的相同对象?我本以为它只会创建自己的独立变量,这意味着我应该将writer改为静态类变量

这是代码中的空指针异常,请尝试在静态方法上使用synchronized块

   synchronized(Logger.class){
或者另一种方法是将整个方法设置为同步,如下所示

public static synchronized void printToGameLog(String value){


我不认为这里需要同步,只有当您的状态是从多个线程读取/写入时才需要同步

因为有单独的日志文件,我不明白为什么需要进行类级同步。似乎是一个不必要的瓶颈。我会分别为每个方法提供同步(因为它们可以同时命中不同的文件):


这是对你的问题的另一种看法。它使用一个线程来写入日志文件,只有这个线程可以访问这些文件。必须对BlockingQueue写入日志的线程:

public class ThreadedLog {

    //This is some code to test the logger
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {

        ThreadedLog log = new ThreadedLog("/tmp/test.txt");
        // Start 100 thread that write against the log
        for (int i = 0; i < 100; i++) {
            new Thread(new TestLogger(log)).start();
        }
    }

    private static class TestLogger implements Runnable {

        private ThreadedLog log;

        public TestLogger(ThreadedLog log) {
            this.log = log;
        }

        @Override
        public void run() {
            for (int i = 0; i < 5000; i++) {
                try {
                    log.log("This is entry " + i + " from thread " + Thread.currentThread().getId());
                } catch (InterruptedException ex) {
                }
            }
            System.out.println(Thread.currentThread().getId() + " is done");
        }
    }
     //________________________________________________________________________________________________
    /*
     * This is the code for the actual logger
     *
     */
    private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(10000);
    private String fileName;
    private Thread thread;
    private Writer writer;

    public ThreadedLog(String fileName) throws UnsupportedEncodingException, FileNotFoundException {
        this.fileName = fileName;
        thread = new Thread(new LoggingThread());
        writer = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream(fileName, true), "utf-8"));
        thread.start();
    }

    private class LoggingThread implements Runnable {

        @Override
        public void run() {

            try {
                for (;;) {
                    ThreadedLog.this.writer.write(queue.take() + "\r\n");
                    ThreadedLog.this.writer.flush();
                }
            } catch (InterruptedException | IOException e) {
                e.printStackTrace();
                try {
                    ThreadedLog.this.writer.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    public void log(String string) throws InterruptedException {
        queue.put(string);
    }
}
公共类ThreadedLog{
//这是一些测试记录器的代码
公共静态void main(字符串[]args)引发不受支持的DencodingException、FileNotFoundException{
ThreadedLog log=newthreadedlog(“/tmp/test.txt”);
//启动100个针对日志写入的线程
对于(int i=0;i<100;i++){
新线程(新测试记录器(日志)).start();
}
}
私有静态类TestLogger实现可运行{
私有线程日志;
公共测试记录器(线程日志){
this.log=log;
}
@凌驾
公开募捐{
对于(int i=0;i<5000;i++){
试一试{
log.log(“这是来自线程“+thread.currentThread().getId())的条目“+i+”;
}捕获(中断异常例外){
}
}
System.out.println(Thread.currentThread().getId()+“完成”);
}
}
//________________________________________________________________________________________________
/*
*这是实际记录器的代码
*
*/
私有最终阻塞队列=新的ArrayBlockingQueue(10000);
私有字符串文件名;
私有线程;
私人作家;
public ThreadedLog(字符串文件名)引发不支持的DencodingException、FileNotFoundException{
this.fileName=文件名;
线程=新线程(新日志线程());
writer=new BufferedWriter(new OutputStreamWriter(
新的FileOutputStream(fileName,true),“utf-8”);
thread.start();
}
私有类LoggingThread实现Runnable{
@凌驾
公开募捐{
试一试{
对于(;;){
ThreadedLog.this.writer.write(queue.take()+“\r\n”);
ThreadedLog.this.writer.flush();
}
}捕获(中断异常| IOE异常){
e、 printStackTrace();
试一试{
ThreadedLog.this.writer.close();
}捕获(例外情况除外){
}
}
}
}
公共无效日志(字符串)引发InterruptedException{
queue.put(字符串);
}
}

如果您正在写入两个不同的文件,则无需同步。不要使用
“\r\n”
——只使用
“\n”
,让运行时为平台写入正确的行结尾。您的目标是协调GameLog和ServerLog的输出,还是仅仅为了防止两个线程在一条输出线内交错?我相信后者。我遇到两个线程可能同时尝试写入同一个文件的情况。谢谢你给我的提示。当然,这将给NPE。我想我会重写我的问题,使其在初始化后在编写器上同步。然而,根据您的建议,这是否意味着当一个线程正在写入游戏日志时,另一个线程可以被阻止写入服务器日志?是的,我认为这是您想要做的,我现在意识到我误解了您的建议queestion@RogerJarvis您还需要在每种情况下关闭该文件。我想这种方法的好处是线程不必花费时间等待锁释放。我想不出比其他方法有什么缺点?有一个缺点。如果您的应用程序或服务器崩溃,并且队列中仍有一些内容需要记录,则这些内容将丢失。如果你能接受这一点,这可能是一个很好的解决方案。
public class Logger
{
    private static final Object GAME_LOG_LOCK = new Object();
    private static final Object SERVER_LOG_LOCK = new Object();

    public static void printToGameLog(String value){
        synchronized (GAME_LOG_LOCK) {
            Writer writer = null;
            try {
                writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("GameLog.txt", true), "utf-8"));
                writer.write(outputString + "\r\n");
            } catch (IOException ex){
                System.out.println("cannot create log file");
            } 
        }
    }

    public static void printToServerLog(String value){
        synchronized (SERVER_LOG_LOCK) {   
            Writer writer = null;
            try {
                writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("serverLog.txt", true), "utf-8"));
                writer.write(outputString + "\r\n");
            } catch (IOException ex){
                  System.out.println("cannot create log file");
            }
        }
    }
}
public class ThreadedLog {

    //This is some code to test the logger
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {

        ThreadedLog log = new ThreadedLog("/tmp/test.txt");
        // Start 100 thread that write against the log
        for (int i = 0; i < 100; i++) {
            new Thread(new TestLogger(log)).start();
        }
    }

    private static class TestLogger implements Runnable {

        private ThreadedLog log;

        public TestLogger(ThreadedLog log) {
            this.log = log;
        }

        @Override
        public void run() {
            for (int i = 0; i < 5000; i++) {
                try {
                    log.log("This is entry " + i + " from thread " + Thread.currentThread().getId());
                } catch (InterruptedException ex) {
                }
            }
            System.out.println(Thread.currentThread().getId() + " is done");
        }
    }
     //________________________________________________________________________________________________
    /*
     * This is the code for the actual logger
     *
     */
    private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(10000);
    private String fileName;
    private Thread thread;
    private Writer writer;

    public ThreadedLog(String fileName) throws UnsupportedEncodingException, FileNotFoundException {
        this.fileName = fileName;
        thread = new Thread(new LoggingThread());
        writer = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream(fileName, true), "utf-8"));
        thread.start();
    }

    private class LoggingThread implements Runnable {

        @Override
        public void run() {

            try {
                for (;;) {
                    ThreadedLog.this.writer.write(queue.take() + "\r\n");
                    ThreadedLog.this.writer.flush();
                }
            } catch (InterruptedException | IOException e) {
                e.printStackTrace();
                try {
                    ThreadedLog.this.writer.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    public void log(String string) throws InterruptedException {
        queue.put(string);
    }
}