import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class Count {
private int count = 0;
//private Random rand = new Random(10);
public synchronized int increment() {
return ++count;
}
public synchronized int getCount() {
return count;
}
}
class Entrance implements Runnable {
private static Count count = new Count();
private static List<Entrance> entrances = new ArrayList<Entrance>();
private int number = 0;
private final int id;
private static volatile boolean canceled = false;
public static void cancel() {
canceled = true;
}
public Entrance(int id) {//id表示花园有多少个入口
this.id = id;
entrances.add(this);
}
public void run() {
while(!canceled) {//没有cancel,就一直运行
synchronized (this) {//this-->Entrance,对Entrance对象加锁了
++number;
}
System.out.println(this+",总共进入花园人数->"+count.increment());
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Stopping "+this);
}
public synchronized int getValue() {//获取单个花园入口的人数
return number;
}
public String toString() {
return "花园入口"+id+"号进入人数->"+getValue();
}
public static int getTotalCount() {
return count.getCount();
}
public static int sumEntrances() {
int sum = 0;
for(Entrance entrance:entrances) {
sum+=entrance.getValue();
}
return sum;
}
}
public class GardenPeople {
public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<5;i++) {
es.execute(new Entrance(i));
}
TimeUnit.MILLISECONDS.sleep(500);
Entrance.cancel();
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务,execute提交的任务都会关闭
es.shutdown();
if(!es.awaitTermination(250, TimeUnit.MILLISECONDS)) {
System.out.println("Some tasks were not terminated !");
}
System.out.println("Total : "+Entrance.getTotalCount());
System.out.println("Sum of Entrances : "+Entrance.sumEntrances());
}
}
上面的例子是摘自《JAVA编程思想》
很好的一个例子,内容就是,一个花园,有多个入口,现在需要通过多线程来记录通过不同的入口进来,最终一共有多少人员进入了该花园。
volatile修饰符是为了确保该变量在同一时间只能有一个线程去访问,当然这种方法肯定没有synchronized更好。
在主函数中,通过一个循环,new出了花园的所有入口,通过字段id来表示花园入口。
在类Entrance类中,我们可以看到很多字段,number是用来表示该入口的进入人数的总数。每new一个Entrance,number=0
count是一个Count对象,用来表示目前为止,一共进入花园的人数总数,所有的入口都算。为什么能做到这样呢,上面的number每次都是0,而这里的count却可以不断的累加,就是因为count用了static来修饰了,所以它只要new了第一次,后面就不会再new了。它不依赖于类特定的实例,被类的所有实例共享。
下面是运行结果:
花园入口0号进入人数->1,总共进入花园人数->1
花园入口2号进入人数->1,总共进入花园人数->3
花园入口1号进入人数->1,总共进入花园人数->2
花园入口3号进入人数->1,总共进入花园人数->4
花园入口4号进入人数->1,总共进入花园人数->5
花园入口0号进入人数->2,总共进入花园人数->6
花园入口2号进入人数->2,总共进入花园人数->9
花园入口4号进入人数->2,总共进入花园人数->10
花园入口1号进入人数->2,总共进入花园人数->7
花园入口3号进入人数->2,总共进入花园人数->8
花园入口1号进入人数->3,总共进入花园人数->11
花园入口3号进入人数->3,总共进入花园人数->15
花园入口2号进入人数->3,总共进入花园人数->14
花园入口4号进入人数->3,总共进入花园人数->13
花园入口0号进入人数->3,总共进入花园人数->12
花园入口2号进入人数->4,总共进入花园人数->16
花园入口4号进入人数->4,总共进入花园人数->19
花园入口0号进入人数->4,总共进入花园人数->20
花园入口3号进入人数->4,总共进入花园人数->18
花园入口1号进入人数->4,总共进入花园人数->17
花园入口0号进入人数->5,总共进入花园人数->21
花园入口2号进入人数->5,总共进入花园人数->23
花园入口3号进入人数->5,总共进入花园人数->22
花园入口1号进入人数->5,总共进入花园人数->25
花园入口4号进入人数->5,总共进入花园人数->24
花园入口2号进入人数->6,总共进入花园人数->27
花园入口1号进入人数->6,总共进入花园人数->28
花园入口3号进入人数->6,总共进入花园人数->26
花园入口4号进入人数->6,总共进入花园人数->30
花园入口0号进入人数->6,总共进入花园人数->29
Stopping 花园入口0号进入人数->6
Stopping 花园入口2号进入人数->6
Stopping 花园入口3号进入人数->6
Stopping 花园入口1号进入人数->6
Stopping 花园入口4号进入人数->6
Total : 30
Sum of Entrances : 30
从结果中,我们可以很清楚的看到,并发同步的过程,还有线程的终止shutdown()。