2

我正在打印信息以使用可重入锁测试线程。我正在使用语句 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 次相同的语句。但是,当我看到每个线程都以相同的顺序显示打印时,我没有得到输出。例如

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。

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

4

3 回答 3

8

我正在创建 10 个线程,并且所有线程都应该在执行此控制台打印语句的地方执行 3 次相同的语句。但是,当我看到每个线程都以相同的顺序显示打印时,我没有得到输出。例如

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

线程应用程序的特定输出顺序是常见问题解答。在这里查看我的答案:多线程中不需要的输出

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

于 2013-09-16T14:55:14.950 回答
1

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

您可以:

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

最后一个不知道...

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

于 2013-09-16T14:49:34.003 回答
0

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

于 2013-09-16T15:05:39.407 回答