方法一
使用线程池ExecutorService的invokeAll()方法,先将要启动的线程存入集合中,然后一次性启动
public class Account {
private Double money;
Account() {
//定义初始金额 实际从数据库中查询
money = 0D;
}
public synchronized double getMoney() {
return money;
}
//模拟存钱
public synchronized void despoilment(double num) {
money += num;
}
}
class Test{
public static void main(String[] args) {
while (true) {
Account account = new Account();
testPoolMuti(account);
}
}
//用100个线程同时向同一个账户存钱
private static void testPoolMuti(Account account) {
ExecutorService executorService = Executors.newFixedThreadPool(100);
List<Callable<String>> tasks = new LinkedList<>();
int i = 100;
while (i-- > 0) {
synchronized (account) {
tasks.add(() -> {
account.despoilment(1D);
return "当前剩余金额" + account.getMoney();
});
}
}
try {
executorService.invokeAll(tasks);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
executorService.shutdown();
}
System.out.println("Account的账户余额为:" + account.getMoney());
}
}
输出结果
性能分析
方法二
使用线程池+CountDownLatch实现,原理是利用CountDownLatch的await()方法,该方法会让线程等待,直到countDown()的返回值等于0时开始执行
class Test{
public static void main(String[] args) {
while (true) {
Account account = new Account();
testPool(account);
}
}
//用100个线程同时向同一个账户存钱
private static void testPool(Account account) {
ExecutorService executorService = Executors.newFixedThreadPool(100);
CountDownLatch countDownLatch = new CountDownLatch(100);//线程计数器
int i = 100;
while (i-- > 0) {
ThreadRun run = new ThreadRun(account, countDownLatch);
executorService.submit(run);
}
try {
countDownLatch.await();
System.out.println("Account的账户余额为:" + account.getMoney());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class ThreadRun implements Runnable {
CountDownLatch countDownLatch;
Account account;
ThreadRun(Account account) {
this.account = account;
}
ThreadRun(Account account, CountDownLatch countDownLatch) {
this.account = account;
this.countDownLatch = countDownLatch;
}
@Override
public synchronized void run() {
account.despoilment(1D);
countDownLatch.countDown();
}
}
输出结果
性能分析
总结:
线程池的额invokeAll方法可以让多个线程同时启动,但是只能使用Callable类实现,线程并行执行,同一时刻可以有多个线程处于就绪态,线程总量相对稳定。线程池+线程计数器方法实现更加自由,但是线程串行执行,同一时刻只有一个线程处于就绪态,大量线程同时涌入会导致等待线程过多,且触发gc数量相对较少。