1、线程池的简介
线程池(英语:thread pool):是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
下面是我在网上收集的关于Java多线程和线程池的学习资料。
学习资料1:《Java多线程》
学习资料2:《Java线程池 ExecutorService》
学习资料3:《Java线程池类ThreadPoolExecutor、ScheduledThreadPoolExecutor及Executors工厂类》
学习资料4:《Java线程池实现秒杀功能》
2、Java线程池实现秒杀功能
【示例】Java使用多线程和Redis实现一个1000人秒杀100部手机的实例。
(1)秒杀实现(SecondKill.java):创建多线程,并利用Redis的事务功能,实现秒杀功能。
package com.pjb.seckill;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.List;
/**
* 秒杀抢购
* @author pan_junbiao
**/
public class SecondKill implements Runnable
{
String iphone = "iphone";
Jedis jedis = new Jedis("127.0.0.1",6379);
String userInfo;
public SecondKill(String userInfo)
{
this.userInfo = userInfo;
}
@Override
public void run()
{
try
{
jedis.watch(iphone); //watchkeys
String val = jedis.get(iphone);
int valint = Integer.valueOf(val);
if(valint<=100 && valint>=1)
{
//1、使用MULTI命令开启事务
Transaction tx = jedis.multi();
//2、事务命令入队
tx.incrBy("iphone",-1);
//3、使用EXEC命令执行事务
//提交事务。如果此时watchkeys被改动了,则返回null
List<Object> list = tx.exec();
if(list==null || list.size()==0)
{
String failuserinfo = "fail_" + userInfo;
String failinfo = "用户:" + failuserinfo + "商品争抢失败,抢购失败";
System.out.println(failinfo);
//抢购失败业务逻辑
jedis.setnx(failuserinfo,failinfo);
}
else
{
for(Object succ : list)
{
String succuserinfo = "succ_" + succ.toString() + "_" + userInfo;
String succinfo = "用户:" + succuserinfo + " 抢购成功,当前抢购成功人数:" + (1 -(valint -100));
System.out.println(succinfo);
//抢购成功业务逻辑
jedis.setnx(succuserinfo,succinfo);
}
}
}
else
{
String failuserinfo = "kcfail_" + userInfo;
String failinfo1 = "用户:" + failuserinfo + " 商品被抢购完毕,抢购失败";
System.out.println(failinfo1);
jedis.setnx(failuserinfo,failinfo1);
//Thread.sleep(500);
return;
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
jedis.close();
}
}
}
(2)主程序(SecondKillTest.java):秒杀功能的入口程序,用于创建线程池,同时生成用户ID,调用秒杀功能代码,完成秒杀任务。
package com.pjb.seckill;
import com.pjb.util.RedisHelper;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Redis秒杀功能的实现,1000人抢购100部手机
* @author pan_junbiao
**/
public class SecondKillTest
{
public static void main(String[] args)
{
RedisHelper redisHelper = new RedisHelper();
final String iphone = "iphone";
//20个线程池并发数
ExecutorService executor = Executors.newFixedThreadPool(20);
final Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.del(iphone); //先删除
jedis.set(iphone,"100"); //设置起始的抢购数
jedis.close();
for(int i=0; i<1000; i++)
{
String userInfo = "pan_junbiao的博客" + i;
executor.execute(new SecondKill(userInfo));
}
executor.shutdown();
}
}
执行结果:
3、Java线程池实现定时任务功能
【示例】Java使用 java.util.concurrent.ScheduledExecutorService 来实现定时任务。
package com.pjb.seckill;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 使用ScheduledExecutorService实现定时任务
* @author pan_junbiao
*/
public class Task
{
public static void main(String[] args)
{
//1、创建线程任务
Runnable runnable = new Runnable()
{
public void run()
{
System.out.println("您好,欢迎访问 pan_junbiao的博客");
}
};
//2、创建线程池
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
//3、线程池绑定线程任务并执行(第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间)
service.scheduleAtFixedRate(runnable, 10, 1, TimeUnit.SECONDS);
}
}
执行结果: