System.out.printf()语句是异步的吗?

时间:2013-09-16 14:45:16

标签: java multithreading output

我正在打印信息以使用Reentrant锁测试线程。我使用语句new ReentrantLock(true)创建公平锁。

在我使用锁的对象方法之一中,我正在使用方法,例如

method() {
    for (int n = 0; n < 3; n++) {
       System.out.printf("%s: processing data \n",
            Thread.currentThread().getName(), data.get());
       TimeUnit.SECONDS.sleep(1);
    }
}

我正在创建10个线程,并且所有线程应执行相同的语句3次执行此控制台print语句。但是,我没有得到输出,我看到每个线程以相同的顺序显示打印。 e.g。

Thread 1: processing data hjjjj
Thread 2: processing data ghhjj
Thread 3: processing  data uiyiii
Thread 2: processing data ghfrtu
......
......

虽然我期待如下:

Thread 1: processing data hjjjj
Thread 2: processing data ghhjj
Thread 3: processing  data uiyiii
Thread 1: processing data uiyuii

是因为公平性在起作用,但是system.out.println的打印顺序与打印命令的顺序不一致?

这是我的课程..

public class PriceInfo {
    private double price1 =1d, price2=2d;
    ReadWriteLock lock = new ReentrantReadWriteLock(true);

    public double getPrice1() {
        lock.readLock().lock();
        try{
            return price1;
        }finally{
            lock.readLock().unlock();
        }
    }

    public double getPrice2() {
        lock.readLock().lock();
        try{
            return price2;
        }finally{
            lock.readLock().unlock();
        }
    }

    public void getPrices() {
        lock.readLock().lock();
        try{
            synchronized (System.out) {
                System.out.printf("%s: price1 = %f and price2 = %f \n",        Thread.currentThread().getName(), price1, price2);
                System.out.flush();
            }
        }finally{
            lock.readLock().unlock();
        }
    }

    public void setPrices(double p1, double p2) {
        lock.writeLock().lock();
        try{
            System.out.println(Thread.currentThread().getName() + ": starting to set new prices ");
            price1 = p1;
            price2 = p2;
            System.out.println(Thread.currentThread().getName() + ": prices changed to price1:"+ p1 + "price2: "+ p2);
        }finally{
            lock.writeLock().unlock();
        }
    }
}

现在还有另一个班..

public class Reader implements Runnable {

    private PriceInfo info;
    public Reader(PriceInfo inf) {
        info = inf;
    }
    @Override
    public void run() {
        for (int i=0; i<2; i++) {
            info.getPrices();
        }
     }
}

最后,我们有作家线程和主要课程。

public class Writer implements Runnable{

    private PriceInfo info;
    public Writer(PriceInfo inf) {
        info = inf;
    }
    @Override
    public void run() {
        for (int i=0; i<2; i++) {
                info.setPrices(new Double(Math.random()*10).doubleValue(), new Double(Math.random()*9).doubleValue());
            try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }

    public static void main(String[] args) {

        PriceInfo pricesInfo=new PriceInfo();

        // create 5 threads and 5 readers
        Reader readers[]=new Reader[5];
        Thread threadsReader[]=new Thread[5];
        for (int i=0; i<5; i++){
            readers[i]=new Reader(pricesInfo);
            threadsReader[i]=new Thread(readers[i],("Thread" + i));
        }

        // create  writer thread

        Writer writer=new Writer(pricesInfo);
        Thread threadWriter=new Thread(writer,"WriterThread");

        for (int i=0; i<5; i++){
                threadsReader[i].start();
            }
            threadWriter.start();
    }
}

我得到以下输出..

   Thread0: price1 = 1.000000 and price2 = 2.000000 
   Thread4: price1 = 1.000000 and price2 = 2.000000 
   Thread3: price1 = 1.000000 and price2 = 2.000000 
   Thread2: price1 = 1.000000 and price2 = 2.000000 
   Thread1: price1 = 1.000000 and price2 = 2.000000 
   WriterThread: starting to set new prices 
   WriterThread: prices changed to price1:3.971662648848391price2: 8.604830021768233
   Thread0: price1 = 3.971663 and price2 = 8.604830 
   Thread1: price1 = 3.971663 and price2 = 8.604830 
   Thread2: price1 = 3.971663 and price2 = 8.604830 
   Thread3: price1 = 3.971663 and price2 = 8.604830 
   Thread4: price1 = 3.971663 and price2 = 8.604830 
   WriterThread: starting to set new prices 
   WriterThread: prices changed to price1:3.0036555312769297price2: 5.15672274505239

所以,你可以看到执行的线程序列是 thread0,thread4,3,2,1,writer,0,1,2,3,4 而我期望按照公平政策,我们应该有相同的序列,如0,4,3,2,1 0,4,3,2,1。

我的代码有问题,还是公平政策不严格?

3 个答案:

答案 0 :(得分:8)

  

我正在创建10个线程,并且所有线程应执行相同的语句3次执行此控制台print语句。但是,我没有得到输出,我看到每个线程以相同的顺序显示打印。 e.g。

特定的输出序列很难(并且不必要)来获取线程。 System.out.printf(...)是一个同步操作,因此输出永远不会相互重叠,但由于一次运行多个线程所固有的竞争条件,输出行的顺序是不可预测的。就异步(与线程同步无关)而言,默认情况下System.out启用了自动刷新,因此每次写入都会刷新PrintStream的所有写入

线程应用程序的特定输出顺序是FAQ。请在此处查看我的回答:unwanted output in multithreading

引用答案,由于硬件,竞争条件,时间切片随机性和其他因素,无法预测线程运行的顺序。

答案 1 :(得分:1)

System.out是一个缓冲流。这意味着它不会同步填充控制台。 虽然printf()调用是同步的,但控制台输出不是。

你可以:

    通过调用System.out.flush();
  • flush()System.out
  • 使用自动刷新流的println()
  • 使用不是AFAIK缓冲的System.err

不确定最后一个......

请注意,您的线程是并发执行的(如果您使用.start())这意味着您不能指望没有同步元素的任何执行顺序。

答案 2 :(得分:0)

虽然很难在没有看到代码启动线程的情况下回答这个问题,但这似乎与System.out.printf()的行为没有任何关系。您正在启动的线程是相互独立地唤醒和休眠,因此线程之间打印的行的顺序取决于运行代码的JVM。如果您需要按顺序使用语句,但想要并行完成工作,可以使用CyclicBarrier来协调打印语句。