案例介绍:
假如某网上商城推出活动,新上架10部新手机免费送客户体验,要求所有参与活动的人员在规定的时间同时参与秒杀挣抢,假如有20人同时参与了该活动,请使用线程池模拟这个场景,保证前10人秒杀成功,后10人秒杀失败;
1:使用线程池创建线程
2:解决线程安全问题
思路提示:
1:既然商品总数量是10个,那么我们可以在创建线程池的时候初始化线程数是10个及以下,设计线程池最大数量为10个;
2:当某个线程执行完任务之后,可以让其他秒杀的人继续使用该线程参与秒杀;
3:使用synchronized控制线程安全,防止出现错误数据;
代码步骤:
1:编写任务类,主要是送出手机给秒杀成功的客户;
2:编写主程序类,创建20个任务(模拟20个客户);
3:创建线程池对象并接收20个任务,开始执行任务;
(代码演示参考idea)
package com.itheima.demo05;
包含了商品数量,客户名称,送手机的行为;
public class MyTask implements Runnable {
private static int id = 10;
private String userName;
public MyTask(String userName) {
this.userName = userName;
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(userName+"正在使用"+name+"参与秒杀任务...");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (MyTask.class){
if(id>0){
System.out.println(userName+"使用"+name+"秒杀:"+id-- +"号商品成功啦!");
}else {
System.out.println(userName+"使用"+name+"秒杀失败啦!");
package com.itheima.demo05;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
主程序类,测试任务类
public class MyTest {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,1, TimeUnit.MINUTES,new LinkedBlockingQueue<>(15));
for (int i = 1; i <=20 ; i++) {
MyTask myTask = new MyTask("客户"+i);
pool.submit(myTask);
pool.shutdown();
案例介绍:
设计一个程序,使用两个线程模拟在两个地点同时从一个账号中取钱,假如卡中一共有1000元,每个线程取800元,要求演示结果一个线程取款成功,剩余200元,另一个线程取款失败,余额不足;
1:使用线程池创建线程
2:解决线程安全问题
思路提示:
1:线程池可以利用Executors工厂类的静态方法,创建线程池对象;
2:解决线程安全问题可以使用synchronized方法控制取钱的操作
3:在取款前,先判断余额是否足够,且保证余额判断和取钱行为的原子性;
(代码演示参考idea)
package com.itheima.demo06;
public class MyTask implements Runnable {
private String userName;
private double money;
private static double total = 1000;
public MyTask(String userName, double money) {
this.userName = userName;
this.money = money;
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(userName+"正在准备使用"+name+"取款:"+money+"元");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (MyTask.class){
if(total-money>0){
System.out.println(userName+"使用"+name+"取款:"+money+"元成功,余额:"+(total-money));
total-=money;
}else {
System.out.println(userName+"使用"+name+"取款:"+money+"元失败,余额:"+total);
package com.itheima.demo06;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class MyTest {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2, new ThreadFactory() {
int id = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ATM" + id++);
});
for (int i = 1; i <=2 ; i++) {
MyTask myTask = new MyTask("客户" + i, 800);
pool.submit(myTask);
pool.shutdown();
线程池的使用步骤可以归纳总结为五步 :
1:利用Executors工厂类的静态方法,创建线程池对象;
2:编写Runnable或Callable实现类的实例对象;
3:利用ExecutorService的submit方法或ScheduledExecutorService的schedule方 法提交并执行线程任务
4:如果有执行结果,则处理异步执行结果(Future)
5:调用shutdown()方法,关闭线程池
区别 | 进程 | 线程 |
---|
根本区别 | 作为资源分配的单位 | 调度和执行的单位 |
开销 | | |
所处环境 | | |
分配内存 | | |
包含关系 | | |