Java 编程思想的这个 OrnamentalGarden 例子为什么是这种打印结果?
这是 java 编程思想的一个小例子,大概意思,五个 Runnable 对象会对自己加锁(但对自己加锁,因为没有别人和它本身冲突,所以没有意义),还有个 Count 对象,它也有同步方法,五个线程都会调到它,自然,只有它的同步方法才是有意义的。
import java.util.concurrent.*; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import static net.mindview.util.Print.*; class Count { private int count = 0; private Random rand = new Random(47); // Remove the synchronized keyword to see counting fail: public synchronized int increment() { int temp = count; System.out.println(Thread.currentThread().getName()+" befor yield"); if(rand.nextBoolean()) // Yield half the time Thread.yield(); System.out.println(Thread.currentThread().getName()+" after yield"); return (count = ++temp); } public synchronized int value() { return count; } } class Entrance implements Runnable { private static Count count = new Count(); private static List<Entrance> entrances = new ArrayList<Entrance>(); private int number = 0; // Doesn't need synchronization to read: private final int id; private static volatile boolean canceled = false; // Atomic operation on a volatile field: public static void cancel() { canceled = true; } public Entrance(int id) { this.id = id; // Keep this task in a list. Also prevents // garbage collection of dead tasks: entrances.add(this); } public void run() { while(!canceled) { synchronized(this) { ++number; } print(this + " Total: " + count.increment()); try { TimeUnit.MILLISECONDS.sleep(100); } catch(InterruptedException e) { print("sleep interrupted"); } } print("Stopping " + this); } public synchronized int getValue() { return number; } public String toString() { return "Entrance " + Thread.currentThread().getName() + ": " + getValue(); } public static int getTotalCount() { return count.value(); } public static int sumEntrances() { int sum = 0; for(Entrance entrance : entrances) sum += entrance.getValue(); return sum; } } public class OrnamentalGarden { public static void main(String[] args) throws Exception { AtomicInteger a = new AtomicInteger(); ExecutorService exec = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),new ThreadFactory(){ public Thread newThread(Runnable r) { return new Thread(r, "pool_" + a.getAndIncrement()); }}); for(int i = 0; i < 5; i++) exec.execute(new Entrance(i)); // Run for a while, then stop and collect the data: TimeUnit.SECONDS.sleep(3); Entrance.cancel(); exec.shutdown(); if(!exec.awaitTermination(250, TimeUnit.MILLISECONDS)) print("Some tasks were not terminated!"); print("Total: " + Entrance.getTotalCount()); print("Sum of Entrances: " + Entrance.sumEntrances()); } }
可能好多人看到这里直接略过了,但我看完这个例子确实似懂非懂的。https://paste.ubuntu.com/p/B7GQMcMhv7/ ,这是原版代码,为了看到简单的线程名,稍微改了下。执行完后,打印结果是:
pool_0 befor yield pool_0 after yield pool_2 befor yield pool_2 after yield pool_4 befor yield pool_4 after yield pool_3 befor yield pool_3 after yield pool_1 befor yield pool_1 after yield Entrance pool_0: 1 Total: 1 Entrance pool_3: 1 Total: 4 为啥这里直接是 4 了? Entrance pool_1: 1 Total: 5 Entrance pool_2: 1 Total: 2 Entrance pool_4: 1 Total: 3 pool_0 befor yield pool_0 after yield
如上,为啥那里直接是 4 了?那个 4 是 count 对象的同步方法,按理说应该接下来打印 2 啊。所以这个程序是想说明,1 过了直接打印 4,是因为线程调度吗?作者想说明什么啊
PS:有时候感觉 Java 编程思想的例子好恶心。。。