@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface NeedSetValue {
Class<?> beanClass();
String param();
String method();
String targetFiled();
}
@Component
@Aspect
public class SetFieldValueAspect {
@Autowired
BeanUtil beanUtil;
@Around("@annotation(com.lvshen.demo.annotation.NeedSetValueField)")
public Object doSetFieldValue(ProceedingJoinPoint point) throws Throwable {
Object o = point.proceed();
if (o instanceof Collection) {
this.beanUtil.setFieldValueForCol(((Collection) o));
} else {
//返回结果不是集合的逻辑
}
return o;
}
}
@NeedSetValueField
public List<Member> listMemberVO(List<Integer> codes) {
List<Member> members = Lists.newArrayList();
for (Integer code : codes) {
Member memberByCode = getMemberByCode(code);
members.add(memberByCode);
}
return members;
}
收录了阿里面试题com.lvshen.demo.arithmetic.alibabatest
;
/**
* Description:面试题002 已知sqrt (2)约等于1.414,要求不用数学库,求sqrt (2)精确到小数点后10位。
*
* @author Lvshen
* @version 1.0
* @date: 2020/4/24 17:40
* @since JDK 1.8
*/
public class Test1 {
private static final double EPSINON = 0.0000000001;
public static double sqrt2() {
double low = 1.4;
double high = 1.5;
double mid = (low + high) / 2;
while (high - low > EPSINON) {
if ((mid * mid > 2)) {
high = mid;
} else {
low = mid;
}
mid = (high + low) / 2;
}
return mid;
}
public static void main(String[] args){
System.out.println(sqrt2());
}
}
JDK的队列com.lvshen.demo.arithmetic.deque
;
@Test
public void test1() {
Deque<String> arrayDeque = new ArrayDeque<>();
//arrayDeque.addLast("t1");
arrayDeque.addFirst("t2");
arrayDeque.addFirst("t3");
arrayDeque.addFirst("t4");
arrayDeque.addFirst("t5");
//arrayDeque.addLast("t6");
log.info(arrayDeque.toString());
//String pop = arrayDeque.pop();
String removeLast = arrayDeque.removeLast();
log.info(arrayDeque.toString());
log.info(removeLast);
}
抽奖算法com.lvshen.demo.arithmetic.lottery
;
/**整体思想: 奖品集合 + 概率比例集合 将奖品按集合中顺序概率计算成所占比例区间,放入比例集合。并产生一个随机数 *加入其中,排序。 排序后,随机数落在哪个区间,就表示那个区间的奖品被抽中。
*返回的随机数在集合中的索引,该索引就是奖品集合中的索引。 比例区间的计算通过概率相加获得。
*/
public static int draw(List<Double> giftProbList) {
List<Double> sortRateList = new ArrayList<>();
// 计算概率总和
Double sumRate = 0D;
for (Double prob : giftProbList) {
sumRate += prob;
}
if (sumRate != 0) {
double rate = 0D; // 概率所占比例
for (Double prob : giftProbList) {
rate += prob;
// 构建一个比例区段组成的集合(避免概率和不为1)
sortRateList.add(rate / sumRate);
}
// 随机生成一个随机数,并排序
//double random = Math.random();
ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
double random = threadLocalRandom.nextDouble(0, 1);
sortRateList.add(random);
Collections.sort(sortRateList);
// 返回该随机数在比例集合中的索引
return sortRateList.indexOf(random);
}
return -1;
}
最大公约数与最小公倍数算法com.lvshen.demo.arithmetic.maxCommon
;
/**
* 欧几里得算法
* 两个非零整数的最大公约数等于其中较小的那个数和两个数相除余数的最大公约数
* @param n
* @param m
* @return
*/
private int getMaxCommonFromEuclid(int m, int n) {
log.info("testStart....");
// m和n的最大公约数 = n 和 m%n的最大公约数
if (n == 0) {
return m;
} else {
return getMaxCommonFromEuclid(n, m % n);
}
}
@Test
public void test2() {
int n = 6;
int m = 20;
int maxCommon = getMaxCommonFromEuclid(n, m);
System.out.println("最大公约数:" + maxCommon);
System.out.println("最小公倍数:" + n * m / maxCommon);
}
队列使用com.lvshen.demo.arithmetic.queue
;
/**
* Description:算法 新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问 QQ 号, 小哈当然不会直接告诉小哼啦,原因嘛你懂的。所以小哈给了小哼一串加密过的数字,同
* 时小哈也告诉了小哼解密规则。规则是这样的:首先将第 1 个数删除,紧接着将第 2 个数放到这串数的末尾,再将第 3个数删除并将第 4 个数再放到这串数的末尾,再将第 5
* 个数删除……直到剩下最后一个数,将最后一个数也删除。按照刚才删除的顺序,把这些 删除的数连在一起就是小哈的 QQ 啦。现在你来帮帮小哼吧。小哈给小哼加密过的一串数 是“6 3 1 75 8 9 2 4”。
*/
/**
* 采用队列方法
*/
@Test
public void test2() {
Queue<Integer> queue = new LinkedList<>();
Integer[] q = { 6, 3, 1, 7, 5, 8, 9, 2, 4 };
List<Integer> list = Lists.newArrayList();
for (int i = 0; i < q.length; i++) {
queue.offer(q[i]);
}
while (queue.element() != null) {
list.add(queue.poll());
queue.offer(queue.poll());
System.out.println(queue);
}
System.out.println(list.toString());
}
搜索算法【广度优先与深度优先】com.lvshen.demo.arithmetic.search
;
public void BFSSearch(String startPoint) {
queue.add(startPoint);
status.put(startPoint,false);
bfsLoop();
}
public void DFSSearch(String startPoint) {
stack.push(startPoint);
status.put(startPoint, true);
dfsLoop();
}
//深度优先
private void dfsLoop() {
if (stack.isEmpty()) {
return;
}
String stackTopPoint = stack.peek();
Map<String, List<String>> graphData = initGraphData();
List<String> neighborPoints = graphData.get(stackTopPoint);
neighborPoints.stream().forEach(x -> {
if (status.getOrDefault(x,false)) {
stack.push(x);
status.put(x, true);
dfsLoop();
}
});
String popPoint = stack.pop();
System.out.println(popPoint);
}
//广度优先
private void bfsLoop() {
String currentQueueHeader = queue.poll();
status.put(currentQueueHeader, true);
System.out.println(currentQueueHeader);
Map<String, List<String>> graphData = initGraphData();
List<String> neighborPoints = graphData.get(currentQueueHeader);
neighborPoints.stream().forEach(x -> {
if (!status.getOrDefault(x, false)) {
if (queue.contains(x)) {
log.info("the point is in queue!");
}
queue.add(x);
status.put(x, false);
}
});
if (!queue.isEmpty()) {
bfsLoop();
}
}
Redis长链转短链算法com.lvshen.demo.arithmetic.shorturl
;
public String getShortUrl(String longUrl, Decimal decimal) {
String cache = redisTemplate.opsForValue().get(CACHE_KEY_PREFIX + longUrl);
if (cache != null) {
log.info("从缓存【{}】中获取到:{}",CACHE_KEY_PREFIX + longUrl,cache);
return LOCALHOST + toOtherBaseString(Long.valueOf(cache), decimal.x);
}
Long num = redisTemplate.opsForValue().increment(SHORT_URL_KEY);
redisTemplate.opsForValue().set(SHORT_LONG_PREFIX + num, longUrl);
redisTemplate.opsForValue().set(CACHE_KEY_PREFIX + longUrl, String.valueOf(num), CACHE_SECONDS, TimeUnit.SECONDS);
return LOCALHOST + toOtherBaseString(num, decimal.x);
}
@Test
public void testShortUrl() {
String url = "www.google.com";
String shortUrl = shortUrlUtil.getShortUrl(url, ShortUrlUtil.Decimal.D64);
System.out.println("短链:" + shortUrl);
}
雪花算法com.lvshen.demo.arithmetic.snowflake
;
public synchronized long next() {
long nowTimestamp = timeGen();
if (nowTimestamp < lastTimestamp) {
throw new IllegalStateException("系统时钟有误");
}
// 当前时间戳跟上次的时间戳一样,毫秒内生成序列
if (lastTimestamp == nowTimestamp) {
/* 生成序列的掩码,127 (1111111=0x7f=127) */
long sequenceMask = 127L;
sequence = (sequence + 1) & sequenceMask;
// 毫秒内序列溢出
if (sequence == 0) {
// 阻塞到下一个毫秒,获得新的时间戳
nowTimestamp = timeGen();
while (nowTimestamp <= lastTimestamp) {
nowTimestamp = timeGen();
}
lastTimestamp = nowTimestamp;
}
} else {
sequence = 0;
lastTimestamp = nowTimestamp;
}
//Date formatDate = DateTimeUtils.getFormatDate("2027-09-03");
//nowTimestamp = formatDate.getTime();
//同一服务器上面的不同应用可能生成同一id
long id2Long = ((nowTimestamp - baseTimestamp) << TIMESTAMP_LEFT_SHIFT) | workId | sequence;
return id2Long;
}
@org.junit.Test
public void test1() throws ParseException {
String id = new SnowFlakeGenerator().nextId();
System.out.println("id生成成功:" + id + ",长度:" + id.length());
}
排序算法com.lvshen.demo.arithmetic.sort
;
@Test
public void test1() {
// 1.插入排序
// printArrays(insertionSort(array));
// 2.冒泡排序
// printArrays(bubbleSort(array));
// 3.选择排序
// printArrays(selectionSort(array));
// 4.希尔排序
// printArrays(shellSort(array));
// 5.快速排序
printArrays(quickSort(array,0,4));
/*// 6.归并排序
printArrays(mergeSort(array));
// 7.计数排序
printArrays(countingSort(array));
// 8.堆排序
printArrays(heapSort(array));*/
// 9.桶排序
// printLists(bucketSort(Ints.asList(array), 5));
//10.基数排序
// printArrays(radixSort(array));
}
栈使用com.lvshen.demo.arithmetic.stack
;
//回文数判断
private boolean palindromeTest(String param) {
if (StringUtils.isBlank(param)) {
return false;
}
Stack<String> stack = new Stack<>();
char[] chars = param.toCharArray();
int mid = chars.length / 2;
for (int i = 0; i < mid; i++) {
stack.push(String.valueOf(chars[i]));
}
for (int i = mid + 1; i <= chars.length - 1; i++) {
// 栈首获取
if (!stack.peek().equals(String.valueOf(chars[i]))) {
break;
}
// 出栈
stack.pop();
}
if (stack.size() == 0) {
return true;
} else {
return false;
}
}
@Test
public void test() {
String param = "席主席";
System.out.println(palindromeTest(param));
}
订单编号生成算法com.lvshen.demo.arithmetic.tradno
;
public static void main(String[] args) throws UnknownHostException {
// 1.两位随机数+13位时间戳
int r1 = (int) (Math.random() * (10));// 产生2个0-9的随机数
int r2 = (int) (Math.random() * (10));
long now = System.currentTimeMillis();// 一个13位的时间戳
String paymentID = String.valueOf(r1) + String.valueOf(r2) + String.valueOf(now);// 订单ID
System.out.println(paymentID);
// 2.年月日+用户主键.hashCode()+ip
InetAddress addrs = InetAddress.getLocalHost();
System.out.println("Local HostAddress: " + addrs.getHostAddress());
String hostName = addrs.getHostName();
System.out.println("Local host name: " + hostName);
String userId = "admin";
// 当前时间
Date date = new Date();
// 转换格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
// 格式化
String time = simpleDateFormat.format(date);
// ip地址
String ip = addrs.getHostAddress();
ip = ip.replace(".", "");
System.currentTimeMillis(); // 获取毫秒
String id = time + ip + userId.hashCode() + System.currentTimeMillis();
System.out.println("生成唯一订单号" + id);
System.out.println("订单号" + ip + System.currentTimeMillis());
}
幂等注解com.lvshen.demo.autoidempotent
;
@AutoIdempotent
@PostMapping("/test/Idempotence")
public ServerResponse testIdempotence() {
return testService.testIdempotence();
}
/**
* 检验token
*
* @param request
* @return
*/
@Override
public boolean checkToken(HttpServletRequest request) throws Exception {
String token = request.getHeader(HEADER_KEY);
if (StringUtils.isBlank(token)) {// header中不存在token
token = request.getParameter(HEADER_KEY);
if (StringUtils.isBlank(token)) {// parameter中也不存在token
throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg());
}
}
if (!redisTemplate.hasKey(token)) {
throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
}
boolean remove = redisTemplate.delete(token);
if (!remove) {
throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
}
return true;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//被ApiIdempotment标记的扫描
AutoIdempotent methodAnnotation = method.getAnnotation(AutoIdempotent.class);
if (methodAnnotation != null) {
try {
return tokenService.checkToken(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示
} catch (Exception ex) {
ResultVo failedResult = ResultVo.getFailedResult(101, ((ServiceException) ex).getMsg());
writeReturnJson(response, JSONObject.toJSONString(failedResult));
throw ex;
}
}
//必须返回true,否则会被拦截一切请求
return true;
}
BigDecimal使用com.lvshen.demo.bigdecimal
;
@Test
public void test(){
BigDecimal bigDecimal = new BigDecimal(0.1);
System.out.println(bigDecimal);
BigDecimal bigDecimal1 = new BigDecimal(10);
System.out.println(bigDecimal1);
BigDecimal bigDecimal2 = new BigDecimal("0.1");
System.out.println(bigDecimal2);
BigDecimal bigDecimal3 = BigDecimal.valueOf(0.1);
System.out.println(bigDecimal3);
}
CAS使用:com.lvshen.demo.cas
;
public class MyAtomicInteger {
private volatile int value;
private static long offset;//偏移地址
private static Unsafe unsafe;
static {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
unsafe = (Unsafe) theUnsafeField.get(null);
Field field = MyAtomicInteger.class.getDeclaredField("value");
offset = unsafe.objectFieldOffset(field);//获得偏移地址
} catch (Exception e) {
e.printStackTrace();
}
}
public void increment(int num) {
int tempValue;
do {
tempValue = unsafe.getIntVolatile(this, offset);//拿到值
} while (!unsafe.compareAndSwapInt(this, offset, tempValue, value + num));//CAS自旋
}
public int get() {
return value;
}
}
volatile使用:com.lvshen.demo.concurrent
;
public class VolatileVisibilityTest {
//private static volatile boolean initFlag = false;
private static boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
System.out.println("waiting data");
while (!initFlag) {
//System.out.println();
//里面添加锁共享变量就不会缓存
synchronized (VolatileVisibilityTest.class) {
}
}
System.out.println("========success!!!");
}).start();
Thread.sleep(2000);
new Thread(() -> prepareData()).start();
}
private static void prepareData() {
System.out.println("开始修改initFlag...");
initFlag = true;
System.out.println("initFlag修改成功...");
}
}
日期处理:com.lvshen.demo.date
;
public Date getDate(String dateStr) throws ParseException {
dateStr = dateStr.replace("Z", " UTC");//是空格+UTC
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");//格式化的表达式
return format.parse(dateStr);
}
instanceof使用:com.lvshen.demo.extendsTest
;
private void testType(Object o) {
if (o instanceof Person) {
System.out.println("this is person");
} else if (o instanceof Student) {
System.out.println("this is student");
}
}
Integer使用:com.lvshen.demo.integer
;
public class IntegerTest {
public static void main(String[] args) {
// -128--127之间
Integer i1 = 100;
Integer i2 = 100;
if (i1 == i2) {
System.out.println("i1 == i2");
} else {
System.out.println("i1 != i2 ");
}
if (i1 < i2) {
}
// 大于127
Integer i3 = 200;
Integer i4 = 200;
/*if (i3 == i4) {
System.out.println("i3 == i4");
} else {
System.out.println("i3 != i4 "); (√)}*/
/*if (i3.compareTo(i4) == 0) {
System.out.println("i3 == i4"); (√)
} else {
System.out.println("i3 != i4 ");
}*/
if (i3.intValue() == i4.intValue()) {
System.out.println("i3 == i4");
} else {
System.out.println("i3 != i4 ");
}
}
@Test
public void testInteger() {
String str = "12";
int parseInt = Integer.parseInt(str);
Integer valueOf = Integer.valueOf(str);
System.out.println("parseInt" + parseInt);
System.out.println("valueOf" + valueOf);
}
}
地址传递与值传递:com.lvshen.demo.javafoundation
;
/**
* 基本数据类型:值传递
*/
@Test
public void test() {
int x = 10;
int y = 20;
swap(x, y);
System.out.println("x[2] = " + x);
System.out.println("y[2] = " + y);
}
/**
* 引用数据类型:地址传递(数组)
*/
@Test
public void test2() {
int[] a = { 10, 20 };
System.out.println("a[0] :" + a[0] + ", a[1] : " + a[1]);
swap(a, 0, 1);
System.out.println("a[0] :" + a[0] + ", a[1] : " + a[1]);
}
SecureRandom使用:com.lvshen.demo.securerandom
;
@Test
public void test2() {
byte[] bytes = new byte[128];
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(System.currentTimeMillis());
secureRandom.nextBytes(bytes);
}
StringBuilder使用:com.lvshen.demo.stringbuildertest
;
抽象工厂,适配器,桥接,建造者,组合,装饰者,外观,工厂,原型,代理,单列....
见博客文章:手写Zookeeper分布式锁
@Override
public void lock() {
if (!tryLock()) {
//没获得锁,阻塞自己
log.info("线程{}没有获得锁,开始阻塞。",Thread.currentThread().getName());
waitForLock();
//再次尝试
lock();
}
}
@Override
public boolean tryLock() { //不会阻塞
//创建节点
if (this.currentPath == null) {
currentPath = this.client.createEphemeralSequential(lockPath + "/", "lock");
}
List<String> children = this.client.getChildren(lockPath);
Collections.sort(children);
if (currentPath.equals(lockPath + "/" + children.get(0))) {
return true;
} else {
int currentIndex = children.indexOf(currentPath.substring(lockPath.length() + 1));
beforePath = lockPath + "/" + children.get(currentIndex - 1);
}
log.info("锁节点创建成功:{}", lockPath);
System.out.println(String.format("锁节点创建成功:{%s}", lockPath));
return false;
}
private void waitForLock() {
CountDownLatch count = new CountDownLatch(1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) throws Exception {
}
@Override
public void handleDataDeleted(String s) throws Exception {
log.info("收到节点{}被删除了",s);
System.out.println(String.format("收到节点[%s]被删除了",s));
count.countDown();
}
};
client.subscribeDataChanges(this.beforePath, listener);
//自己阻塞自己
if (this.client.exists(this.beforePath)) {
try {
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取消注册
client.unsubscribeDataChanges(this.beforePath, listener);
}
public static void exportExcel(String exportPath) {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("测试");
for (int i = 0; i < 9; i++) {
sheet.setColumnWidth(i, 4300);
}
setTitleStyle(sheet, workbook);
setExcelFooterName("test", 0, workbook);
exportOutPutExcel(exportPath, workbook);
}
Optional
,Collections
,String
,Primitives
/**
* 基本数据类型:值传递
*/
@Test
public void test() {
int x = 10;
int y = 20;
swap(x, y);
System.out.println("x[2] = " + x);
System.out.println("y[2] = " + y);
}
/**
* 引用数据类型:地址传递(数组)
*/
@Test
public void test2() {
int[] a = { 10, 20 };
System.out.println("a[0] :" + a[0] + ", a[1] : " + a[1]);
swap(a, 0, 1);
System.out.println("a[0] :" + a[0] + ", a[1] : " + a[1]);
}
@Component
@Slf4j
public class KafkaConsumer {
@KafkaListener(topics = "${spring.kafka.topic}")
public void listen(ConsumerRecord<?, ?> record) {
log.info("topic={}, offset={}, message={}", record.topic(), record.offset(), record.value());
}
}
@Component
@Slf4j
public class KafkaProducer {
@Autowired
private KafkaTemplate kafkaTemplate;
@Value("${spring.kafka.topic}")
private String topic;
/**
* 发送kafka消息
*
* @param jsonString
*/
public void send(String jsonString) {
ListenableFuture future = kafkaTemplate.send(topic, jsonString);
future.addCallback(o -> log.info("kafka消息发送成功:" + jsonString), throwable -> log.error("kafka消息发送失败:" + jsonString));
}
}
@Test
public void testDemo() throws InterruptedException {
log.info("start send");
kafkaProducer.send("中文测试222");
log.info("end send");
// 休眠10秒,为了使监听器有足够的时间监听到topic的数据
Thread.sleep(10);
}
@Override
public void lock() {
if (!tryLock()) {
//抢不到锁的线程放入阻塞队列中排队
waiters.add(Thread.currentThread());
while (true) {
if (tryLock()) {
waiters.poll();//抢到锁,自己移出队列
return;
} else {
//阻塞
LockSupport.park();
}
}
}
}
@Override
public boolean tryLock() {
if (state.get() == 0) {
if (state.compareAndSet(0, 1)) {
ownerThread = Thread.currentThread();
return true;
}
//可重入锁设计
} else if (ownerThread == Thread.currentThread()) {
state.set(state.get() + 1);
}
return false;
}
@Override
public void unlock() {
if (ownerThread != Thread.currentThread()) {
throw new RuntimeException("非法调用,当前线程并没有持有该锁");
}
if (state.decrementAndGet() == 0) {
ownerThread = null;
//通知其他等待抢锁的线程
Thread waiterThread = waiters.peek();
if (waiterThread != null) {
LockSupport.unpark(waiterThread);
}
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Member implements Serializable {
private String id;
private String name;
private Integer code;
@Transient
@NeedSetValue(beanClass = BeanClassTest.class, param = "code", method = "getMemberByCode", targetFiled = "name")
private String annotationParam;
}
@Mapper
public interface MemberMapper {
List<Member> listByName(String name);
}
@Service
public class MemberService {
@Autowired
private MemberMapper memberMapper;
@Cacheable(value = "member",key = "#name")
public List<Member> listByName(String name) {
return memberMapper.listByName(name);
}
}
@RestController
@RequestMapping(value = "/member", method = {RequestMethod.GET, RequestMethod.POST})
public class MemberController {
@Autowired
private MemberService memberService;
@RequestMapping("/listByName")
@ResponseBody
public List<Member> listByName(String name) {
return memberService.listByName(name);
}
}
<mapper namespace="com.lvshen.demo.member.mapper.MemberMapper">
<resultMap id="result" type="com.lvshen.demo.member.entity.Member">
<result property="name" column="name"/>
<result property="id" column="id"/>
<result property="code" column="code"/>
</resultMap>
<select id="listByName" resultMap="result">
SELECT * FROM member where name=#{name}
</select>
</mapper>
缓存注解,延迟队列,分布式锁,限流注解,可重入锁,分布式session,发布订阅
@Component
@Aspect
@Slf4j
public class CacheAspect {
@Autowired
private RedisTemplate redisTemplate;
@Pointcut("@annotation(com.lvshen.demo.redis.cache.CustomizeCache)")
public void cachePointcut() {
}
@Around("cachePointcut()")
public Object doCache(ProceedingJoinPoint point) {
Object value = null;
Semaphore semaphore = null;
MethodSignature signature = (MethodSignature) point.getSignature();
try {
//获取方法上注解的类容
Method method = point.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes());
CustomizeCache annotation = method.getAnnotation(CustomizeCache.class);
String keyEl = annotation.key();
String prefix = annotation.value();
long expireTimes = annotation.expireTimes();
int semaphoreCount = annotation.semaphoreCount();
//解析SpringEL表达式
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(keyEl);
StandardEvaluationContext context = new StandardEvaluationContext();
//添加参数
Object[] args = point.getArgs();
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
for (int i = 0; i < parameterNames.length; i++) {
context.setVariable(parameterNames[i], args[i].toString());
}
//解析
String key = prefix + "::" + expression.getValue(context).toString();
//判断缓存中是否存在
value = redisTemplate.opsForValue().get(key);
if (value != null) {
log.info("从缓存中读取到值:{}", value);
return value;
}
//自定义组件,如:限流,降级。。。
//创建限流令牌
semaphore = new Semaphore(semaphoreCount);
boolean tryAcquire = semaphore.tryAcquire(3000L, TimeUnit.MILLISECONDS);
if (!tryAcquire) {
//log.info("当前线程【{}】获取令牌失败,等带其他线程释放令牌", Thread.currentThread().getName());
throw new RuntimeException(String.format("当前线程【%s】获取令牌失败,等带其他线程释放令牌", Thread.currentThread().getName()));
}
//缓存不存在则执行方法
value = point.proceed();
//同步value到缓存
redisTemplate.opsForValue().set(key, value, expireTimes, TimeUnit.SECONDS);
} catch (Throwable t) {
t.printStackTrace();
} finally {
if (semaphore == null) {
return value;
} else {
semaphore.release();
}
}
return value;
}
}
@RequestMapping(value = "/testSession",method = RequestMethod.GET)
public String testSession(HttpSession session, Model model) {
List<Member> members = memberService.listMember();
System.out.println("sessionId------>" + session.getId());
model.addAttribute("member", JSON.toJSONString(members));
session.setAttribute("member",JSON.toJSONString(members));
return "hello world";
}
@Service
public class Publisher {
@Autowired
private RedisTemplate redisTemplate;
public void pushMessage(String topic, RedisMessage message) {
redisTemplate.convertAndSend(topic,message);
}
}
@Slf4j
public class UserReceiver extends AbstractReceiver {
@Override
public void receiveMessage(Object message) {
log.info("接收到用户消息:{}", JSON.toJSONString(message));
}
}
//redis发布订阅 pub/sub
@Test
public void pushMessage() {
UserMessage userMessage = new UserMessage();
userMessage.setMsgId(UUID.randomUUID().toString().replace("-", ""));
userMessage.setUserId("1");
userMessage.setUsername("admin");
userMessage.setUsername("root");
userMessage.setCreateStamp(System.currentTimeMillis());
publisher.pushMessage("user", userMessage);
GoodsMessage goodsMessage = new GoodsMessage();
goodsMessage.setMsgId(UUID.randomUUID().toString().replace("-", ""));
goodsMessage.setGoodsType("苹果");
goodsMessage.setNumber("十箱");
goodsMessage.setCreateStamp(System.currentTimeMillis());
publisher.pushMessage("goods", goodsMessage);
}
@Component
public class RedisWithReentrantLock {
@Autowired
private RedisTemplate redisTemplate;
private static final String REDIS_VALUE = "r_lock";
private ThreadLocal<Map<String, Integer>> lockers = new ThreadLocal<>();
private boolean _lock(String key) {
return redisTemplate.opsForValue().setIfAbsent(key, REDIS_VALUE, 20, TimeUnit.SECONDS);
}
private void _unlock(String key) {
redisTemplate.delete(key);
}
private Map<String, Integer> currentLockers() {
Map<String, Integer> refs = lockers.get();
if (refs != null) {
return refs;
}
lockers.set(new HashMap<>());
return lockers.get();
}
public boolean lock(String key) {
Map<String, Integer> refs = currentLockers();
Integer refCnt = refs.get(key);
if (refCnt != null) {
refs.put(key, refCnt + 1);
return true;
}
boolean ok = this._lock(key);
if (!ok) {
return false;
}
refs.put(key, 1);
return true;
}
public boolean unlock(String key) {
Map<String, Integer> refs = currentLockers();
Integer refCnt = refs.get(key);
if (refCnt == null) {
return false;
}
refCnt = refCnt - 1;
if ((refCnt > 0)) {
refs.put(key, refCnt);
} else {
refs.remove(key);
this._unlock(key);
}
return true;
}
}
见博客文章:BIO与NIO与多路复用
public static void main(String[] args){
Student student = new Student();//.var
Main.student = new Student();// .filed 全局变量
Student student1 = new Student(); //Student.new
Student student2 = (Student) new Object(); //new Object().castvar
if (student == null) { //student.null
}
if (student != null) { //student.notnull
}
boolean flag = true;
if (flag) { //flag.if
}
while (flag) { //flag.while
}
System.out.println(flag); //flag.sout
//return flag; flag.return
String[] strs = new String[5];
for (int i = 0; i < strs.length; i++) { //strs.fori
}
for (String str : strs) { //strs.for
}
for (int i = strs.length - 1; i >= 0; i--) { //strs.forr
}
try {
main(new String[]{}); //main.try
} catch (Exception e) {
e.printStackTrace();
}
List<Member> members =new ArrayList<>(); //Member.list
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//6.调用
try {
doDispatch(req, resp);
} catch (Exception e) {
resp.getWriter().write("500 Exception Detail " + Arrays.toString(e.getStackTrace()));
}
}
@Override
public void init(ServletConfig config) {
//1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
//2.扫描相关的类
doScanner(configProperties.getProperty("scanPackage"));
//3.实例化相关的类
doInstance();
//4.完成依赖注入
doAutowired();
//5.初始化HandlerMapping
doInitHandlerMapping();
}
//评测题目: 三个线程A、B、C,实现一个程序让线程A打印“A”,线程B打印“B”,线程C打印“C”,
//三个线程输出ABCABCABC......ABC,循环10次“ABC”
//30分钟
二分查找和冒泡排序
/**
* Description:给出有序数组(非递减)和闭区间, 找出数组中在区间之内的元素起始位置和结束位置
* 输入:
* 1. 有序数组[1,1,2,3,4,5,5]
* 2. 闭区间[-3,3]
* 输出:[0,3]
* 解释:在数组中,前4个元素在区间之内,则起始位置为0,结束位置为3
* 要求:最坏情况时间复杂度小于O(n)
*
* @author Lvshen
* @version 1.0
* @date: 2020/4/27 18:56
* @since JDK 1.8
*/
public class SemaphoreDemo {
public static void main(String[] args) {
SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
int count = 9; //数量
//循环屏障
CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
Semaphore semaphore = new Semaphore(5);//限制请求数量
for (int i = 0; i < count; i++) {
String vipNo = "vip-00" + i;
new Thread(() -> {
try {
cyclicBarrier.await();
//semaphore.acquire();//获取令牌
boolean tryAcquire = semaphore.tryAcquire(3000L, TimeUnit.MILLISECONDS);
if (!tryAcquire) {
System.out.println("获取令牌失败:" + vipNo);
}
//执行操作逻辑
System.out.println("当前线程:" + Thread.currentThread().getName());
semaphoreDemo.service(vipNo);
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
}
}
// 限流控制5个线程同时访问
public void service(String vipNo) throws InterruptedException {
System.out.println("楼上出来迎接贵宾一位,贵宾编号" + vipNo + ",...");
Thread.sleep(new Random().nextInt(3000));
System.out.println("欢送贵宾出门,贵宾编号" + vipNo);
}
}
public class CountDownLatchDemo {
static final int COUNT = 20;
static CountDownLatch cdl = new CountDownLatch(COUNT);
public static void main(String[] args) throws Exception {
new Thread(new Teacher(cdl)).start();
Thread.sleep(1);
for (int i = 0; i < COUNT; i++) {
new Thread(new Student(i, cdl)).start();
}
synchronized (CountDownLatchDemo.class) {
CountDownLatchDemo.class.wait();
}
}
static class Teacher implements Runnable {
CountDownLatch cdl;
Teacher(CountDownLatch cdl) {
this.cdl = cdl;
}
@Override
public void run() {
System.out.println("老师发卷子。。。");
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老师收卷子。。。");
}
}
static class Student implements Runnable {
CountDownLatch cdl;
int num;
Student(int num, CountDownLatch cdl) {
this.num = num;
this.cdl = cdl;
}
@Override
public void run() {
System.out.println(String.format("学生(%s)写卷子。。。",num));
//doingLongTime();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("学生(%s)写卷子。。。",num));
cdl.countDown();
}
}
}
public class CyclicBarrierDemo {
static final int COUNT = 5;
public static void main(String[] args) throws Exception {
for (int i = 0; i < COUNT; i++) {
new Thread(new Staff(i, cb)).start();
}
synchronized (CyclicBarrierDemo.class) {
CyclicBarrierDemo.class.wait();
}
}
static CyclicBarrier cb = new CyclicBarrier(COUNT, new Singer());
static class Singer implements Runnable {
@Override
public void run() {
System.out.println("为大家唱歌。。。");
}
}
static class Staff implements Runnable {
CyclicBarrier cb;
int num;
Staff(int num, CyclicBarrier cb) {
this.num = num;
this.cb = cb;
}
@SneakyThrows
@Override
public void run() {
System.out.println(String.format("员工(%s)出发。。。", num));
Thread.sleep(2000);
System.out.println(String.format("员工(%s)到达地点一。。。", num));
try {
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(String.format("员工(%s)再出发。。。", num));
Thread.sleep(2000);
//doingLongTime();
System.out.println(String.format("员工(%s)到达地点二。。。", num));
try {
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(String.format("员工(%s)再出发。。。", num));
Thread.sleep(2000);
//doingLongTime();
System.out.println(String.format("员工(%s)到达地点三。。。", num));
try {
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(String.format("员工(%s)结束。。。", num));
}
}
}
sleep -> TIMED_WAITING
t2中执行t1.join(5000L)
t2的状态:TIMED_WAITING
t2中执行t1.join()
t2的状态:WAITING
t1抢不到锁的状态:BLOCKED
WATTING || BLOCKING
t1 park后的状态:WAITING
t1 unpark后的状态:WAITING
public class MyFutureTask<T> implements Runnable {
Callable<T> callable;
T result;
volatile String state = "NEW";
LinkedBlockingQueue<Thread> queue = new LinkedBlockingQueue<Thread>();
public MyFutureTask(Callable<T> callable) {
this.callable = callable;
}
public T get() {
if ("END".equals(state)) {
return result;
}
while (!"END".equals(state)) {
queue.add(Thread.currentThread());
LockSupport.park();
}
return result;
}
@Override
public void run() {
try {
result = callable.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
state = "END";
}
Thread th = queue.poll();
if (queue != null) {
LockSupport.unpark(th);
th = queue.poll();
}
}
}
public class LockSupportDemo {
static int i = 0;
static Thread t1, t2, t3;
public static void main(String[] args) {
t1 = new Thread(() -> {
while (i < 10) {
System.out.println("t1:" + (++i));
LockSupport.unpark(t2); //t2变为非阻塞
LockSupport.park();
}
});
t2 = new Thread(() -> {
while (i < 10) {
System.out.println(" t2:" + (++i));
LockSupport.unpark(t3);
LockSupport.park();
}
});
t3 = new Thread(() -> {
while (i < 10) {
System.out.println("t3:" + (++i));
LockSupport.unpark(t1);
LockSupport.park();
}
});
t1.start();
t2.start();
t3.start();
}
}
public class ThreadLocalTest {
private static ThreadLocal<Student> threadLocal = new ThreadLocal<>();
@Test
public void test() {
Student student1 = new Student(11, "lvshen");
Student student2 = new Student(22, "niumo");
threadLocal.set(student1);
threadLocal.set(student2);
}
@Test
public void test1() {
printAllSlot(16);
}
private static void printAllSlot(int len) {
System.out.println("************* len = " + len + " ***************");
for (int i = 1; i <= 64; i++) {
ThreadLocal<String> local = new ThreadLocal<>();
int slot = getSlot(local, len);
System.out.print(slot + " ");
if (i % len == 0) {
System.out.println();
}
}
}
static int getSlot(ThreadLocal<?> t, int len) {
int hashCode = getHashCode(t);
return hashCode & (len - 1);
}
static int getHashCode(ThreadLocal<?> t) {
Field field;
try {
field = t.getClass().getDeclaredField("threadLocalHashCode");
field.setAccessible(true);
return (int) field.get(t);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
见博客:我所用到的Java8
LongAddr使用
private LongAdder longAdderVal = new LongAdder();
longAdderVal.increment();
Lambda表达式,foreach
LocalDate
@Test
public void testLocalDate() {
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.of(12, 20);
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
System.out.println("program execute Successful!!!");
}
@Slf4j
public class WatcherApi implements Watcher {
@Override
public void process(WatchedEvent watchedEvent) {
log.info("【Watcher监听事件】={}",watchedEvent.getState());
log.info("【监听路径为】={}",watchedEvent.getPath());
log.info("【监听的类型为】={}",watchedEvent.getType()); // 三种监听类型: 创建,删除,更新
}
}
/**
* 测试方法 初始化
*/
@PostConstruct
public void init() {
String path = "/test/lvshen";
log.info("【执行初始化测试方法。。。。。。。。。。。。】");
//createNode(path, "测试");
String value = getData(path, new WatcherApi());
log.info("【执行初始化测试方法getData返回值。。。。。。。。。。。。】={}", value);
// 删除节点出发 监听事件
//deleteNode(path);
}
@Bean(name = "zkClient")
public ZooKeeper zkClient(){
ZooKeeper zooKeeper=null;
try {
final CountDownLatch countDownLatch = new CountDownLatch(1);
//连接成功后,会回调watcher监听,此连接操作是异步的,执行完new语句后,直接调用后续代码
// 可指定多台服务地址 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
zooKeeper = new ZooKeeper(connectString, timeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
if(Event.KeeperState.SyncConnected==event.getState()){
//如果收到了服务端的响应事件,连接成功
countDownLatch.countDown();
}
}
});
countDownLatch.await();
log.info("【初始化ZooKeeper连接状态....】={}",zooKeeper.getState());
}catch (Exception e){
log.error("初始化ZooKeeper连接异常....】={}",e);
}
return zooKeeper;
}