我正在打印信息以使用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。
我的代码有问题,还是公平政策不严格?
答案 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();
println()
System.err
。 不确定最后一个......
请注意,您的线程是并发执行的(如果您使用.start()
)这意味着您不能指望没有同步元素的任何执行顺序。
答案 2 :(得分:0)
虽然很难在没有看到代码启动线程的情况下回答这个问题,但这似乎与System.out.printf()的行为没有任何关系。您正在启动的线程是相互独立地唤醒和休眠,因此线程之间打印的行的顺序取决于运行代码的JVM。如果您需要按顺序使用语句,但想要并行完成工作,可以使用CyclicBarrier来协调打印语句。