├── README.md ├── src └── main │ └── java │ └── demo │ ├── three │ ├── flow │ │ ├── threadlocal │ │ │ ├── TestInterface.java │ │ │ ├── DomainAbilityBean2.java │ │ │ ├── BeanThree.java │ │ │ ├── FlowGround.java │ │ │ ├── BeanFive.java │ │ │ ├── AsyncRunnable.java │ │ │ └── ContextCache.java │ │ ├── TestDTO.java │ │ ├── DomainAbilityBean.java │ │ ├── BeanTwo.java │ │ ├── BeanOne.java │ │ ├── AsyncComponent.java │ │ ├── StageEnum.java │ │ ├── FlowContent.java │ │ ├── ComponentExecutor.java │ │ ├── AnnotationUtils.java │ │ ├── ApplicationContextHelper.java │ │ ├── FlowStart.java │ │ └── FlowCenter.java │ ├── ConcurrentHashMapDemo.java │ └── CopyOnWriteArrayListDemo.java │ ├── two │ ├── StringDemo.java │ ├── TreeSetDemo.java │ ├── LinkedListDemo.java │ ├── TreeMapDemo.java │ ├── LinkedHashMapDemo.java │ ├── ArraysDemo.java │ ├── HashMapDemo.java │ └── ArrayListDemo.java │ ├── one │ ├── SubClass.java │ ├── ParentInteface.java │ ├── StringDemo1.java │ ├── StringUtils.java │ ├── FinallyDemo.java │ ├── ParentStaticClass.java │ ├── StaticClass.java │ └── StringDemo.java │ ├── other │ ├── TestDTO.java │ ├── TailRecursion.java │ ├── Test0.java │ └── TailRecursionCall.java │ ├── eight │ ├── Lambda.java │ └── LambdaExpressionDemo.java │ ├── four │ ├── Queue.java │ ├── DIYQueueDemo.java │ ├── SynchronousQueueDemo.java │ ├── DIYQueue.java │ └── DelayQueueDemo.java │ ├── sixth │ ├── RefundDemo.java │ ├── SynchronizedDemo.java │ ├── ConditionDemo.java │ ├── CountDownLatchDemo.java │ ├── ShareLock.java │ ├── test.groovy │ ├── BatchRefundDemo.java │ └── MysqlConnection.java │ ├── DemoApplication.java │ ├── ninth │ ├── ThreadLocalDemo.java │ └── socket │ │ ├── SocketService.java │ │ ├── SocketServiceStart.java │ │ └── SocketClient.java │ ├── seven │ └── ThreadPoolExecutorDemo.java │ └── five │ ├── FutureTaskDemo.java │ └── ThreadDemo.java ├── .gitignore └── pom.xml /README.md: -------------------------------------------------------------------------------- 1 | # java8_demo -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/TestInterface.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | 3 | public interface TestInterface { 4 | 5 | R t(T t); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/demo/two/StringDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | import org.junit.Test; 4 | 5 | public final class StringDemo { private String s ="hello";@Test public void say() { System.out.println(s); }} 6 | -------------------------------------------------------------------------------- /src/main/java/demo/one/SubClass.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | /** 4 | * SubClass 5 | * author wenhe 6 | * date 2019/7/29 7 | */ 8 | public class SubClass implements ParentInteface { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/DomainAbilityBean2.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | 3 | /** 4 | * 领域行为,不定义任何方法 5 | * author wenhe 6 | * date 2019/8/11 7 | */ 8 | public interface DomainAbilityBean2 { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/demo/one/ParentInteface.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | 4 | /** 5 | * ParentInteface 6 | *author wenhe 7 | *date 2019/7/29 8 | */ 9 | public interface ParentInteface { 10 | 11 | default void test(){ 12 | // doSomeThing 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/TestDTO.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class TestDTO implements Serializable { 9 | 10 | private Long id; 11 | 12 | private String str; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/demo/one/StringDemo1.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | public class StringDemo1 { 4 | 5 | private final char[] value; 6 | 7 | private final String str; 8 | 9 | public StringDemo1(char[] value,String str1) { 10 | this.value = value; 11 | this.str = str1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/demo/other/TestDTO.java: -------------------------------------------------------------------------------- 1 | package demo.other; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * TestDTO 9 | *author wenhe 10 | *date 2019/9/8 11 | */ 12 | @Data 13 | public class TestDTO { 14 | 15 | private Long begin; 16 | private Long end; 17 | private BigDecimal total; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/demo/two/TreeSetDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | 4 | 5 | import org.junit.Test; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | /** 9 | * TreeMapDemo 10 | * author wenhe 11 | */ 12 | @Slf4j 13 | public class TreeSetDemo { 14 | 15 | 16 | @Test 17 | public void testIterator() { 18 | 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/DomainAbilityBean.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | /** 4 | * 领域行为 author wenhe date 2019/8/11 5 | */ 6 | public interface DomainAbilityBean { 7 | 8 | /** 9 | * 领域行为的方法入口 10 | */ 11 | default FlowContent invoke(FlowContent content) { 12 | return content; 13 | } 14 | 15 | /** 16 | * 领域行为的方法入口2 17 | */ 18 | default void invoke(){ 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/demo/eight/Lambda.java: -------------------------------------------------------------------------------- 1 | package demo.eight; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | /** 6 | * Lambda 7 | *author wenhe 8 | *date 2019/10/12 9 | */ 10 | public class Lambda { 11 | 12 | public static void simple() { 13 | Runnable runnable = () -> System.out.println("lambda is run"); 14 | runnable.run(); 15 | } 16 | public static void main(String[] args) throws Exception { 17 | simple(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/BeanTwo.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | @AsyncComponent 8 | @Component 9 | @Slf4j 10 | public class BeanTwo implements DomainAbilityBean { 11 | 12 | @Override 13 | public FlowContent invoke(FlowContent content) { 14 | log.info("BeanTwo is run,thread name is {}",Thread.currentThread().getName()); 15 | return null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/BeanOne.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | @Component 8 | @Slf4j 9 | public class BeanOne implements DomainAbilityBean { 10 | 11 | @Override 12 | public FlowContent invoke(FlowContent content) { 13 | // 方法的入参从 FlowContent 里面拿 14 | log.info("BeanOne is run,thread name is {}",Thread.currentThread().getName()); 15 | return null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/demo/one/StringUtils.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | /** 4 | * StringUtils 5 | * author wenhe 6 | * date 2019/7/28 7 | */ 8 | public class StringUtils { 9 | 10 | public static final String upperName(String name) { 11 | name = name.substring(0, 1).toUpperCase() + name.substring(1); 12 | return name; 13 | } 14 | 15 | public static final String lownerName(String name) { 16 | name = name.substring(0, 1).toLowerCase() + name.substring(1); 17 | return name; 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/AsyncComponent.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 异步 SpringBean 执行注解 11 | * SpringBean 需要异步执行的话,就打上该注解 12 | *author wenhe 13 | *date 2019/10/7 14 | */ 15 | @Target(ElementType.TYPE)// 表示该注解应该打在类上 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Documented 18 | public @interface AsyncComponent { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/BeanThree.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.Random; 6 | 7 | import demo.three.flow.DomainAbilityBean; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | @Slf4j 11 | @Component 12 | public class BeanThree implements DomainAbilityBean { 13 | 14 | @Override 15 | public void invoke() { 16 | int i = new Random().nextInt(1000); 17 | ContextCache.putAttribute("key1", "value"+i); 18 | log.info("put key1,value{}",i); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/demo/four/Queue.java: -------------------------------------------------------------------------------- 1 | package demo.four; 2 | 3 | /** 4 | * 定义出队列的接口 5 | * author wenhe 6 | * date 2019/9/1 7 | */ 8 | public interface Queue { 9 | 10 | /** 11 | * 放数据 12 | * @param item 入参数 13 | * @return 14 | */ 15 | boolean put(T item); 16 | 17 | /** 18 | * 拿数据 19 | * @return 20 | */ 21 | T take(); 22 | 23 | class Node { 24 | 25 | // 数据本身 26 | T item; 27 | // 下一个元素 28 | Node next; 29 | 30 | // 构造器 31 | public Node(T item) { 32 | this.item = item; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/FlowGround.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * FlowGround 11 | *author wenhe 12 | *date 2019/10/16 13 | */ 14 | @Target(ElementType.METHOD)// 表示该注解应该打在类上 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Documented 17 | public @interface FlowGround { 18 | 19 | 20 | String requestKey(); 21 | 22 | String responseKey(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/StageEnum.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 流程的阶段,步骤 7 | * author wenhe 8 | * date 2019/8/11 9 | */ 10 | @Getter 11 | public enum StageEnum { 12 | 13 | PARAM_VALID("PARAM_VALID", "参数校验"), 14 | 15 | BUSINESS_VALID("BUSINESS_VALID", "业务校验"), 16 | 17 | IN_TRANSACTION("IN_TRANSACTION", "事务中落库"), 18 | 19 | AFTER_TRANSACTION("AFTER_TRANSACTION", "事务后事件"), 20 | ; 21 | 22 | private String code; 23 | private String desc; 24 | 25 | StageEnum(String code, String desc) { 26 | this.code = code; 27 | this.desc = desc; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/RefundDemo.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | 3 | import java.util.Objects; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * 根据商品 ID 进行退款 9 | */ 10 | @Slf4j 11 | public class RefundDemo { 12 | 13 | /** 14 | * 根据商品 ID 进行退款 15 | * @param itemId 16 | * @return 17 | */ 18 | public boolean refundByItem(Long itemId) { 19 | try { 20 | // 线程沉睡 30 毫秒,模拟单个商品退款过程 21 | Thread.sleep(30); 22 | log.info("refund success,itemId is {}", itemId); 23 | return true; 24 | } catch (Exception e) { 25 | log.error("refundByItemError,itemId is {}", itemId); 26 | return false; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/demo/other/TailRecursion.java: -------------------------------------------------------------------------------- 1 | package demo.other; 2 | 3 | import java.util.stream.Stream; 4 | 5 | 6 | /** 7 | * 尾递归优化 递归延迟执行 8 | * author wenhe 9 | * date 2019/9/8 10 | * 11 | */ 12 | @FunctionalInterface 13 | public interface TailRecursion { 14 | 15 | TailRecursion apply(); 16 | 17 | default Boolean isComplete() { 18 | return Boolean.FALSE; 19 | } 20 | 21 | default T getResult() { 22 | throw new RuntimeException("递归还没有结束,暂时得不到结果"); 23 | } 24 | 25 | default T invoke() { 26 | return Stream.iterate(this, TailRecursion::apply) 27 | .filter(TailRecursion::isComplete) 28 | .findFirst() 29 | .get()//执行急方法 30 | .getResult(); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Eclipse project files 2 | .project 3 | .classpath 4 | .settings 5 | #IntelliJ IDEA project files and directories 6 | *.iml 7 | *.ipr 8 | *.iws 9 | .idea/ 10 | #Geany project file 11 | .geany 12 | #KDevelop project file and directory 13 | .kdev4/ 14 | *.kdev4 15 | #Build targets 16 | /target 17 | */target 18 | #Report directories 19 | /reports 20 | */reports 21 | #Mac-specific directory that no other operating system needs. 22 | .DS_Store 23 | 24 | #Scala-play project files 25 | logs 26 | project/project 27 | project/target 28 | target 29 | tmp 30 | .history 31 | dist 32 | /.idea 33 | /*.iml 34 | /out 35 | /.idea_modules 36 | /.classpath 37 | /.project 38 | /RUNNING_PID 39 | /.settings 40 | *.log* 41 | */*.log* 42 | dep.txt 43 | *.rdb -------------------------------------------------------------------------------- /src/main/java/demo/one/FinallyDemo.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | import org.junit.Test; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * FinallyDemo 9 | * author wenhe 10 | * date 2019/7/29 11 | */ 12 | @Slf4j 13 | public class FinallyDemo { 14 | 15 | @Test 16 | public void testCatchFinally() { 17 | try { 18 | log.info("try is run"); 19 | if (true) { 20 | throw new RuntimeException("try exception"); 21 | } 22 | } catch (Exception e) { 23 | log.info("catch is run"); 24 | if (true) { 25 | throw new RuntimeException("catch exception"); 26 | } 27 | } finally { 28 | log.info("finally is run"); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/demo/one/ParentStaticClass.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | /** 11 | * StaticClass 12 | * author wenhe 13 | * date 2019/7/28 14 | */ 15 | @Slf4j 16 | public class ParentStaticClass { 17 | 18 | public static List PARENT_LIST = new ArrayList(){{ 19 | log.info("父类静态变量初始化"); 20 | }}; 21 | 22 | static { 23 | log.info("父类静态块初始化"); 24 | } 25 | 26 | public ParentStaticClass() { 27 | log.info("父类构造器初始化"); 28 | } 29 | 30 | public static void testStatic() { 31 | log.info("父类静态方法被调用"); 32 | } 33 | 34 | public final void testFinal(){ 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/BeanFive.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import demo.three.flow.AsyncComponent; 6 | import demo.three.flow.DomainAbilityBean; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | @Slf4j 10 | @AsyncComponent 11 | @Component 12 | public class BeanFive implements DomainAbilityBean { 13 | 14 | @Override 15 | public void invoke() { 16 | String value = ContextCache.getAttribute("key1"); 17 | try { 18 | Thread.sleep(5000); 19 | } catch (InterruptedException e) { 20 | e.printStackTrace(); 21 | } 22 | log.info("get 线程名称为{}, value is {}", Thread.currentThread().getName(),value); 23 | log.info("------------------"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | import demo.three.flow.ApplicationContextHelper; 7 | import demo.three.flow.FlowContent; 8 | import demo.three.flow.FlowStart; 9 | 10 | 11 | /** 12 | * DemoApplication 13 | *author wenhe 14 | *date 2019/9/24 15 | */ 16 | @SpringBootApplication(scanBasePackages = {"demo"}) 17 | public class DemoApplication { 18 | 19 | public static void main(String[] args) throws InterruptedException { 20 | SpringApplication.run(DemoApplication.class); 21 | for (int i = 0; i < 20; i++) { 22 | ApplicationContextHelper.getBean(FlowStart.class) 23 | .start("flow2", new FlowContent()); 24 | } 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/demo/one/StaticClass.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | /** 11 | * StaticClass 12 | * author wenhe 13 | * date 2019/7/28 14 | */ 15 | @Slf4j 16 | public class StaticClass extends ParentStaticClass{ 17 | 18 | public static List LIST = new ArrayList(){{ 19 | log.info("子类静态变量初始化"); 20 | }}; 21 | 22 | static { 23 | log.info("子类静态块初始化"); 24 | } 25 | 26 | public StaticClass() { 27 | log.info("子类构造器初始化"); 28 | } 29 | 30 | public static void testStatic() { 31 | log.info("子类静态方法被调用"); 32 | } 33 | 34 | 35 | public static void main(String[] args) { 36 | log.info("main 方法执行"); 37 | new StaticClass(); 38 | } 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/FlowContent.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import com.google.common.collect.Maps; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import lombok.Data; 10 | 11 | /** 12 | * 流程上下文 13 | *author wenhe 14 | *date 2019/8/11 15 | */ 16 | @Data 17 | public class FlowContent implements Serializable{ 18 | 19 | private static final long serialVersionUID = -1368014678785056855L; 20 | 21 | /** 22 | * 入参数 23 | */ 24 | private Object request; 25 | 26 | /** 27 | * 出参 28 | */ 29 | private Object response; 30 | 31 | public static void main(String[] args) { 32 | /** 33 | * 第一个 key 是流程的名字 34 | * 第二个 map 的 key 是阶段,为 StageEnum 枚举,值为多个领域行为的集合 35 | */ 36 | Map>> map = Maps.newHashMap(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/demo/other/Test0.java: -------------------------------------------------------------------------------- 1 | package demo.other; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * 简单的递归 7 | * n! = 1*2*3*……(n-1)*n 8 | *author wenhe 9 | *date 2019/9/8 10 | */ 11 | public class Test0 { 12 | 13 | public static BigDecimal recursion(long begin, long end, BigDecimal total) { 14 | if (begin == end) { 15 | return total; 16 | } 17 | return recursion(++begin, end, total.multiply(new BigDecimal(begin))); 18 | } 19 | 20 | public static BigDecimal recursion1(long begin, long end, BigDecimal total) { 21 | if (begin == end) { 22 | return total; 23 | } 24 | ++begin; 25 | total = total.multiply(new BigDecimal(begin)); 26 | return recursion1(begin, end, total);//在方法的最后直接返回,叫做尾调用 27 | } 28 | 29 | public static void main(String[] args) { 30 | BigDecimal total = recursion(1, 9000, BigDecimal.ONE); 31 | System.out.println(total); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/demo/ninth/ThreadLocalDemo.java: -------------------------------------------------------------------------------- 1 | package demo.ninth; 2 | 3 | import com.google.common.collect.Maps; 4 | 5 | import org.junit.Test; 6 | import org.springframework.util.CollectionUtils; 7 | 8 | import java.util.Map; 9 | 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * ThreadLocal 演示 14 | * author wenhe 15 | * date 2019/10/15 16 | */ 17 | @Slf4j 18 | public class ThreadLocalDemo { 19 | 20 | /** 21 | * 上下文 22 | */ 23 | static final ThreadLocal> context = new ThreadLocal<>(); 24 | 25 | @Test 26 | public void testThread() { 27 | Map contextMap = context.get(); 28 | if (CollectionUtils.isEmpty(contextMap)) { 29 | contextMap = Maps.newHashMap(); 30 | } 31 | 32 | contextMap.put("key1", "value1"); 33 | context.set(contextMap); 34 | log.info("key1,value1被放到上下文中"); 35 | 36 | getFromComtext(); 37 | } 38 | 39 | private String getFromComtext() { 40 | String value1 = context.get().get("key1"); 41 | log.info("从 ThreadLocal 中取出上下文,key1 对应的值为:{}", value1); 42 | return value1; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/ComponentExecutor.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import org.springframework.aop.support.AopUtils; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import demo.three.flow.threadlocal.AsyncRunnable; 11 | 12 | /** 13 | * 组件执行器 14 | * author wenhe 15 | * date 2019/10/7 16 | */ 17 | public class ComponentExecutor { 18 | 19 | private static ExecutorService executor = new ThreadPoolExecutor(3, 3, 20 | 365L, TimeUnit.DAYS, 21 | new LinkedBlockingQueue<>()); 22 | 23 | public static final void run(DomainAbilityBean component, FlowContent content) { 24 | if (AnnotationUtils.isAnnotationPresent(AsyncComponent.class, AopUtils.getTargetClass(component))) { 25 | // executor.submit(() -> { component.invoke(content); }); 26 | executor.submit(new AsyncRunnable(() -> component.invoke())); 27 | return; 28 | } 29 | // component.invoke(content); 30 | component.invoke(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/SynchronizedDemo.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | 3 | import com.google.common.collect.Maps; 4 | 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import javax.annotation.PostConstruct; 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | /** 14 | * 共享资源初始化、注册、动态刷新等场景 15 | * 演示使用 synchronized 防止并发 16 | */ 17 | @Slf4j 18 | @Component 19 | public class SynchronizedDemo { 20 | 21 | // 共享资源 22 | private static final Map SHARED_MAP = Maps.newConcurrentMap(); 23 | // 有无加锁完成的标志位 24 | private static boolean loaded = false; 25 | 26 | /** 27 | * 初始化、注册 28 | */ 29 | @PostConstruct 30 | public void init(){ 31 | if(loaded){ 32 | return; 33 | } 34 | synchronized (this){ 35 | if(loaded){ 36 | return; 37 | } 38 | log.info("SynchronizedDemo init begin"); 39 | // 从数据库中捞取数据,组装成 SHARED_MAP 的数据格式 40 | loaded = true; 41 | log.info("SynchronizedDemo init end"); 42 | } 43 | } 44 | 45 | /** 46 | * 刷新 47 | */ 48 | public void refresh(){ 49 | SHARED_MAP.clear(); 50 | SHARED_MAP.putAll(new HashMap<>()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/demo/three/ConcurrentHashMapDemo.java: -------------------------------------------------------------------------------- 1 | package demo.three; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | /** 11 | * ConcurrentHashMapDemo 12 | *author wenhe 13 | *date 2019/8/7 14 | */ 15 | @Slf4j 16 | public class ConcurrentHashMapDemo { 17 | 18 | @Test 19 | public void testTransfer(){ 20 | ConcurrentHashMap map = new ConcurrentHashMap<>(2); 21 | map.put(1,1); 22 | map.put(2,2); 23 | map.put(3,3); 24 | map.put(4,4); 25 | map.put(5,5); 26 | map.put(6,6); 27 | map.put(57,58); 28 | map.put(51,51); 29 | map.put(52,52); 30 | map.put(53,53); 31 | map.put(54,54); 32 | map.put(55,55); 33 | map.put(56,56); 34 | map.put(57,57); 35 | map.put(58,58); 36 | map.put(59,59); 37 | } 38 | 39 | ConcurrentHashMap MAP_1 = new ConcurrentHashMap<>(2); 40 | 41 | @Test 42 | public void testInit(){ 43 | new Thread(() -> MAP_1.put(1, 1)).start(); 44 | new Thread(() -> MAP_1.put(1, 1)).start(); 45 | System.out.println("nihao"); 46 | } 47 | 48 | @Test 49 | public void test33(){ 50 | Map map = new ConcurrentHashMap<>(10); 51 | map.put("nihao","nihao"); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/AsyncRunnable.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.MDC; 5 | 6 | import java.util.HashMap; 7 | 8 | import lombok.Getter; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * AsyncRunnable 13 | * 14 | * @author likongpeng 15 | * @date 2017/9/3 16 | */ 17 | @Slf4j 18 | @Getter 19 | public class AsyncRunnable implements Runnable { 20 | 21 | private Runnable runnable; 22 | private HashMap hashMap = new HashMap(); 23 | 24 | public AsyncRunnable(Runnable runnable) { 25 | this.runnable = runnable; 26 | copy(runnable); 27 | } 28 | 29 | @Override 30 | public void run() { 31 | try { 32 | ContextCache.putAllAttribute(hashMap); 33 | if (null != runnable) { 34 | runnable.run(); 35 | } 36 | } catch (Exception e) { 37 | log.error("[AsyncRunnable-run] has error", e); 38 | throw new RuntimeException(e); 39 | } finally { 40 | hashMap = new HashMap(); 41 | ContextCache.clean(); 42 | } 43 | } 44 | 45 | private void copy(Runnable runnable) { 46 | try { 47 | hashMap.putAll(ContextCache.getMap()); 48 | } catch (Exception e) { 49 | log.error("[AsyncRunnable-copy] has error,runnable is {}", 50 | runnable.toString(), e); 51 | throw new RuntimeException(e); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/demo/two/LinkedListDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.ListIterator; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * LinkedListDemo 13 | *author wenhe 14 | */ 15 | @Slf4j 16 | public class LinkedListDemo extends LinkedList{ 17 | 18 | @Override 19 | public String get(int index) { 20 | return super.get(index); 21 | } 22 | 23 | @Test 24 | public void testItertor(){ 25 | List list = new LinkedList(); 26 | list.add("s1"); 27 | list.add("s3"); 28 | list.add("s3"); 29 | list.add(null); 30 | list.add("s4"); 31 | 32 | for (String s:list){ 33 | if(s == null){ 34 | list.remove(s); 35 | } 36 | } 37 | 38 | for (int i = 0; i < list.size(); i++) { 39 | if(list.get(i).equals("s3")){ 40 | list.remove(i); 41 | } 42 | } 43 | 44 | ListIterator listIterator = list.listIterator(); 45 | while (listIterator.hasNext()){ 46 | String s = listIterator.next(); 47 | log.info("从头到尾迭代顺序:"+s); 48 | } 49 | 50 | while (listIterator.hasPrevious()){ 51 | String s = listIterator.previous(); 52 | if(s.equals("s5")){ 53 | listIterator.remove(); 54 | } 55 | log.info("从尾到头迭代顺序:"+s); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/ConditionDemo.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | 3 | import java.util.concurrent.locks.Condition; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | /** 8 | * 用锁实现了队列的逻辑 9 | * 大家看看这个像那个队列的实现逻辑 10 | *author wenhe 11 | *date 2019/11/1 12 | */ 13 | public class ConditionDemo { 14 | 15 | final Lock lock = new ReentrantLock(); 16 | final Condition notFull = lock.newCondition(); 17 | final Condition notEmpty = lock.newCondition(); 18 | 19 | final Object[] items = new Object[100]; 20 | int putptr, takeptr, count; 21 | 22 | public void put(Object x) throws InterruptedException { 23 | try { 24 | lock.lock(); 25 | while (count == items.length) { 26 | notFull.await(); 27 | } 28 | items[putptr] = x; 29 | if (++putptr == items.length) { 30 | putptr = 0; 31 | } 32 | ++count; 33 | notEmpty.signal(); 34 | } finally { 35 | lock.unlock(); 36 | } 37 | } 38 | 39 | public Object take() throws InterruptedException { 40 | try { 41 | lock.lock(); 42 | while (count == 0) { 43 | notEmpty.await(); 44 | } 45 | Object x = items[takeptr]; 46 | if (++takeptr == items.length) { 47 | takeptr = 0; 48 | } 49 | --count; 50 | notFull.signal(); 51 | return x; 52 | } finally { 53 | lock.unlock(); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/AnnotationUtils.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import java.lang.annotation.Annotation; 4 | 5 | /** 6 | * 注解工具类 7 | *author wenhe 8 | *date 2019/10/7 9 | */ 10 | public class AnnotationUtils { 11 | 12 | /** 13 | * 判断注解是不是当前类的注解 14 | * @param targetAnnotation 15 | * @param annotatedType 16 | * @return boolean 17 | */ 18 | public static boolean isAnnotationPresent(final Class targetAnnotation, 19 | final Class annotatedType) { 20 | return findAnnotation(targetAnnotation, annotatedType) != null; 21 | } 22 | 23 | /** 24 | * 从当前类中找到指定的注解 25 | * @param targetAnnotation 26 | * @param annotatedType 27 | * @param 28 | * @return Annotation 29 | */ 30 | public static A findAnnotation(final Class targetAnnotation, 31 | final Class annotatedType) { 32 | A foundAnnotation = annotatedType.getAnnotation(targetAnnotation); 33 | if (foundAnnotation == null) { 34 | return foundAnnotation; 35 | } 36 | for (Annotation annotation : annotatedType.getAnnotations()) { 37 | Class annotationType = annotation.annotationType(); 38 | if (annotationType.isAnnotationPresent(targetAnnotation)) { 39 | foundAnnotation = annotationType.getAnnotation(targetAnnotation); 40 | break; 41 | } 42 | } 43 | return foundAnnotation; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/ApplicationContextHelper.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * ApplicationContextHelper 10 | * author wenhe 11 | * date 2019/3/21 12 | */ 13 | @Component 14 | public class ApplicationContextHelper implements ApplicationContextAware { 15 | 16 | private static ApplicationContext applicationContext; 17 | 18 | @Override 19 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 20 | ApplicationContextHelper.applicationContext = applicationContext; 21 | } 22 | 23 | public static T getBean(Class targetClz) { 24 | T beanInstance = null; 25 | //byType 26 | try { 27 | beanInstance = (T) applicationContext.getBean(targetClz); 28 | } catch (Exception e) { 29 | } 30 | //byName 31 | if (beanInstance == null) { 32 | String simpleName = targetClz.getSimpleName(); 33 | simpleName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1); 34 | beanInstance = (T) applicationContext.getBean(simpleName); 35 | } 36 | if (beanInstance == null) { 37 | throw new RuntimeException( 38 | "beanName " + targetClz.getSimpleName() 39 | + " can not be found in ApplicationContext (byType and byName)"); 40 | } 41 | return beanInstance; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/demo/two/TreeMapDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | 4 | import com.alibaba.fastjson.JSON; 5 | 6 | import org.junit.Test; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.Comparator; 11 | import java.util.List; 12 | import java.util.TreeMap; 13 | 14 | import lombok.Data; 15 | import lombok.extern.slf4j.Slf4j; 16 | 17 | /** 18 | * TreeMapDemo 19 | * author wenhe 20 | */ 21 | @Slf4j 22 | public class TreeMapDemo { 23 | 24 | @Data 25 | class DTO implements Comparable { 26 | 27 | private Integer id; 28 | 29 | public DTO(Integer id) { 30 | this.id = id; 31 | } 32 | 33 | @Override 34 | public int compareTo(DTO o) { 35 | //默认从小到大排序 36 | return id - o.getId(); 37 | } 38 | } 39 | 40 | 41 | @Test 42 | public void testIterator() { 43 | TreeMap m = new TreeMap<>(); 44 | m.put("asdf","nihao"); 45 | m.put("sdf","nihao"); 46 | m.put("df","nihao"); 47 | m.keySet().iterator(); 48 | } 49 | 50 | @Test 51 | public void testTwoComparable() { 52 | // 第一种排序,从小到大排序,实现 Comparable 的 compareTo 方法进行排序 53 | List list = new ArrayList<>(); 54 | for (int i = 5; i > 0; i--) { 55 | list.add(new DTO(i)); 56 | } 57 | Collections.sort(list); 58 | log.info(JSON.toJSONString(list)); 59 | 60 | // 第二种排序,从大到小排序,利用外部排序器 Comparator 进行排序 61 | Comparator comparator = (Comparator) (o1, o2) -> o2.getId() - o1.getId(); 62 | List list2 = new ArrayList<>(); 63 | for (int i = 5; i > 0; i--) { 64 | list2.add(new DTO(i)); 65 | } 66 | Collections.sort(list,comparator); 67 | log.info(JSON.toJSONString(list2)); 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/threadlocal/ContextCache.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow.threadlocal; 2 | import java.io.Serializable; 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | public class ContextCache implements Serializable { 10 | 11 | private static final long serialVersionUID = 2136539028591849277L; 12 | 13 | // 使用 ThreadLocal 缓存上下文信息 14 | public static final ThreadLocal> CACHE = new InheritableThreadLocal<>(); 15 | 16 | /** 17 | * 放数据 18 | * @param sourceKey 19 | */ 20 | public static final void putAttribute(String sourceKey,String value){ 21 | Map cacheMap = CACHE.get(); 22 | if(null == cacheMap){ 23 | cacheMap = new HashMap<>(); 24 | } 25 | // log.info("putAttribute HashMap 内存地址 is {}",System.identityHashCode(cacheMap)); 26 | cacheMap.put(sourceKey,value); 27 | CACHE.set(cacheMap); 28 | } 29 | 30 | 31 | /** 32 | * 拿数据 33 | * @param sourceKey 34 | */ 35 | public static final String getAttribute(String sourceKey){ 36 | Map cacheMap = CACHE.get(); 37 | // log.info("getAttribute HashMap 内存地址 is {}",System.identityHashCode(cacheMap)); 38 | if(null == cacheMap){ 39 | return null; 40 | } 41 | return cacheMap.get(sourceKey); 42 | } 43 | 44 | /** 45 | * 得到 Map 46 | * @return 47 | */ 48 | public static final Map getMap(){ 49 | return CACHE.get(); 50 | } 51 | 52 | /** 53 | * 54 | * @param map 55 | */ 56 | public static final void putAllAttribute(Map map){ 57 | Map cacheMap = CACHE.get(); 58 | if(null == cacheMap){ 59 | cacheMap = new HashMap<>(); 60 | } 61 | cacheMap.putAll(map); 62 | CACHE.set(cacheMap); 63 | } 64 | 65 | /** 66 | * 清空ThreadLocal的数据 67 | */ 68 | public static void clean() { 69 | CACHE.remove(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/demo/four/DIYQueueDemo.java: -------------------------------------------------------------------------------- 1 | package demo.four; 2 | import java.util.concurrent.LinkedBlockingQueue; 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import org.junit.Test; 6 | 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * 自定义队列测试类 13 | * author wenhe 14 | * date 2019/9/1 15 | */ 16 | @Slf4j 17 | public class DIYQueueDemo { 18 | 19 | private final static Queue queue = new DIYQueue<>(); 20 | 21 | class Product implements Runnable{ 22 | private final String message; 23 | 24 | public Product(String message) { 25 | this.message = message; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | try { 31 | boolean success = queue.put(message); 32 | if (success) { 33 | log.info("put {} success", message); 34 | return; 35 | } 36 | log.info("put {} fail", message); 37 | } catch (Exception e) { 38 | log.info("put {} fail", message); 39 | } 40 | } 41 | 42 | } 43 | 44 | class Consumer implements Runnable{ 45 | @Override 46 | public void run() { 47 | try { 48 | String message = (String) queue.take(); 49 | log.info("consumer message :{}",message); 50 | } catch (Exception e) { 51 | log.info("consumer message fail",e); 52 | } 53 | } 54 | } 55 | 56 | @Test 57 | public void testDIYQueue() throws InterruptedException { 58 | ThreadPoolExecutor executor = 59 | new ThreadPoolExecutor(10,10,0,TimeUnit.MILLISECONDS, 60 | new LinkedBlockingQueue<>()); 61 | for (int i = 0; i < 1000; i++) { 62 | if(i % 2 == 0){ 63 | executor.submit(new Product(i+"")); 64 | continue; 65 | } 66 | executor.submit(new Consumer()); 67 | } 68 | Thread.sleep(10000000); 69 | } 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/demo/seven/ThreadPoolExecutorDemo.java: -------------------------------------------------------------------------------- 1 | package demo.seven; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | import org.junit.Test; 6 | 7 | import java.util.List; 8 | import java.util.concurrent.Callable; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.Future; 11 | import java.util.concurrent.LinkedBlockingQueue; 12 | import java.util.concurrent.ThreadPoolExecutor; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import lombok.extern.slf4j.Slf4j; 16 | 17 | @Slf4j 18 | public class ThreadPoolExecutorDemo { 19 | 20 | private static final int COUNT_BITS = Integer.SIZE - 3; 21 | private static final int CAPACITY = (1 << COUNT_BITS) - 1; 22 | 23 | @Test 24 | public void test() { 25 | System.out.println(COUNT_BITS); 26 | System.out.println(CAPACITY); 27 | final int RUNNING = -1 << COUNT_BITS;//-536870912 28 | final int SHUTDOWN = 0 << COUNT_BITS;//0 29 | final int STOP = 1 << COUNT_BITS;//-536870912 30 | final int TIDYING = 2 << COUNT_BITS;//1073741824 31 | final int TERMINATED = 3 << COUNT_BITS;//1610612736 32 | log.info("RUNNING is {}",ctlOf(RUNNING,0)); 33 | 34 | } 35 | private static int ctlOf(int rs, int wc) { return rs | wc; } 36 | private static int workerCountOf(int c) { return c & CAPACITY; } 37 | private static int runStateOf(int c) { return c & ~CAPACITY; } 38 | 39 | @Test 40 | public void forDebug() throws ExecutionException, InterruptedException { 41 | ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0L, TimeUnit.MILLISECONDS, 42 | new LinkedBlockingQueue(1)); 43 | String result =""; 44 | Callable call = () -> result; 45 | List futures = Lists.newArrayList(); 46 | for (int i = 0; i < 3; i++) { 47 | Future future = executor.submit(call); 48 | futures.add(future); 49 | } 50 | for (Future future : futures) { 51 | System.out.println(future.get()); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/FlowStart.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.util.CollectionUtils; 8 | 9 | import java.util.List; 10 | 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | /** 14 | * 流程启动类 15 | * author wenhe 16 | * date 2019/8/11 17 | */ 18 | @Slf4j 19 | @Component 20 | public class FlowStart { 21 | 22 | /** 23 | * 流程引擎开始 24 | * 25 | * @param flowName 流程的名字 26 | */ 27 | public void start(String flowName, FlowContent content) { 28 | invokeParamValid(flowName, content); 29 | invokeBusinessValid(flowName, content); 30 | invokeInTramsactionValid(flowName, content); 31 | invokeAfterTramsactionValid(flowName, content); 32 | } 33 | 34 | private void invokeParamValid(String flowName, FlowContent content) { 35 | stageInvoke(flowName, StageEnum.PARAM_VALID, content); 36 | } 37 | 38 | private void invokeBusinessValid(String flowName, FlowContent content) { 39 | stageInvoke(flowName, StageEnum.BUSINESS_VALID, content); 40 | } 41 | 42 | private void invokeInTramsactionValid(String flowName, FlowContent content) { 43 | stageInvoke(flowName, StageEnum.IN_TRANSACTION, content); 44 | } 45 | 46 | private void invokeAfterTramsactionValid(String flowName, FlowContent content) { 47 | stageInvoke(flowName, StageEnum.AFTER_TRANSACTION, content); 48 | } 49 | 50 | private void stageInvoke(String flowName, StageEnum stage, FlowContent content) { 51 | List 52 | domainAbilitys = 53 | FlowCenter.flowMap.getOrDefault(flowName, Maps.newHashMap()) 54 | .getOrDefault(stage, Lists.newArrayList()); 55 | if (CollectionUtils.isEmpty(domainAbilitys)) { 56 | //throw new RuntimeException("找不到该流程对应的领域行为" + flowName); 57 | } 58 | for (DomainAbilityBean domainAbility : domainAbilitys) { 59 | // domainAbility.invoke(content); 60 | ComponentExecutor.run(domainAbility,content); 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/demo/other/TailRecursionCall.java: -------------------------------------------------------------------------------- 1 | package demo.other; 2 | 3 | import org.junit.Test; 4 | 5 | import java.math.BigDecimal; 6 | 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | /** 10 | * 尾递归延迟执行通用类 11 | * n! = 1*2*3*……(n-1)*n 12 | *author wenhe 13 | *date 2019/9/8 14 | */ 15 | @Slf4j 16 | public class TailRecursionCall { 17 | 18 | public static TailRecursion call(final TailRecursion nextRecursion) { 19 | return nextRecursion; 20 | } 21 | 22 | public static TailRecursion done(T value) { 23 | return new TailRecursion() { 24 | @Override 25 | public TailRecursion apply() { 26 | throw new RuntimeException("递归已经结束了"); 27 | } 28 | 29 | @Override 30 | public Boolean isComplete() { 31 | return Boolean.TRUE; 32 | } 33 | 34 | @Override 35 | public T getResult() { 36 | return value; 37 | } 38 | }; 39 | } 40 | 41 | public static TailRecursion recursion1(TestDTO testDTO) { 42 | if (testDTO.getBegin().equals(testDTO.getEnd())) { 43 | return TailRecursionCall.done(testDTO.getTotal()); 44 | } 45 | testDTO.setBegin(1+testDTO.getBegin()); 46 | testDTO.setTotal(testDTO.getTotal().multiply(new BigDecimal(testDTO.getBegin()))); 47 | return TailRecursionCall.call(()->recursion1(testDTO)); 48 | } 49 | 50 | // 阶乘计算 51 | public static String recursion(long begin, long end, BigDecimal total) { 52 | // begin 每次计算时都会递增,当 begin 和 end 相等时,计算结束,返回最终值 53 | if (begin == end) { 54 | return total.toString(); 55 | } 56 | // recursion 第三个参数表示当前阶乘的结果 57 | return recursion(++begin, end, total.multiply(new BigDecimal(begin))); 58 | } 59 | 60 | @Test 61 | public void testRecursion() { 62 | // log.info("计算 10 的阶乘,结果为{}",recursion(1, 10, BigDecimal.ONE)); 63 | log.info("计算 9k 的阶乘,结果为{}",recursion(1, 9000, BigDecimal.ONE)); 64 | } 65 | 66 | @Test 67 | public void testRecursion1(){ 68 | TestDTO testDTO = new TestDTO(); 69 | testDTO.setBegin(1L); 70 | testDTO.setEnd(9000L); 71 | testDTO.setTotal(BigDecimal.ONE); 72 | log.info("计算 9k 的阶乘,结果为{}",recursion1(testDTO).invoke()); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/demo/four/SynchronousQueueDemo.java: -------------------------------------------------------------------------------- 1 | package demo.four; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.SynchronousQueue; 9 | 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * SynchronousQueueDemo 14 | *author wenhe 15 | *date 2019/8/18 16 | */ 17 | @Slf4j 18 | public class SynchronousQueueDemo { 19 | 20 | static class Product implements Runnable{ 21 | 22 | private final BlockingQueue queue; 23 | 24 | public Product(BlockingQueue queue) { 25 | this.queue = queue; 26 | } 27 | 28 | @Override 29 | public void run() { 30 | try { 31 | log.info("begin put"); 32 | queue.put(producy("nihao")); 33 | log.info("end put"); 34 | } catch (InterruptedException e) { 35 | } 36 | } 37 | 38 | } 39 | 40 | static class Consumer implements Runnable{ 41 | 42 | private final BlockingQueue queue; 43 | 44 | public Consumer(BlockingQueue queue) { 45 | this.queue = queue; 46 | } 47 | 48 | @Override 49 | public void run() { 50 | try { 51 | log.info("Consumer begin"); 52 | String name = (String) queue.take(); 53 | log.info("Consumer end :{}",name); 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | } 59 | 60 | 61 | static String producy(String name){ 62 | return name; 63 | } 64 | 65 | public static void main(String[] args) throws InterruptedException { 66 | BlockingQueue q = new SynchronousQueue(true); 67 | Product p = new Product(q); 68 | Consumer c = new Consumer(q); 69 | new Thread(c).start(); 70 | log.info("sleeping"); 71 | Thread.sleep(5000L); 72 | log.info("sleepEnd"); 73 | new Thread(p).start(); 74 | } 75 | 76 | @Test 77 | public void testRelQueue(){ 78 | ExecutorService executorService = Executors.newFixedThreadPool(10); 79 | executorService.submit(() -> System.out.println(Thread.currentThread().getName() + " is run")); 80 | 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/demo/ninth/socket/SocketService.java: -------------------------------------------------------------------------------- 1 | package demo.ninth.socket; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStream; 8 | import java.net.Socket; 9 | import java.nio.charset.Charset; 10 | 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | /** 14 | * 任务处理类 15 | *author wenhe 16 | *date 2019/10/26 17 | */ 18 | @Slf4j 19 | public class SocketService implements Runnable { 20 | 21 | private Socket socket; 22 | 23 | public SocketService() { 24 | } 25 | 26 | public SocketService(Socket socket) { 27 | this.socket = socket; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | log.info("SocketService 服务端任务开始执行"); 33 | OutputStream outputStream = null; 34 | InputStream is = null; 35 | InputStreamReader isr = null; 36 | BufferedReader br = null; 37 | try { 38 | //接受消息 39 | socket.setSoTimeout(10000);// 10秒还没有得到数据,直接断开连接 40 | is = socket.getInputStream(); 41 | isr = new InputStreamReader(is,"UTF-8"); 42 | br = new BufferedReader(isr); 43 | StringBuffer sb = SocketClient.segmentRead(br); 44 | socket.shutdownInput(); 45 | log.info("SocketService accept info is {}", sb.toString()); 46 | 47 | //服务端处理 模拟服务端处理耗时 48 | Thread.sleep(2000); 49 | String response = sb.toString(); 50 | 51 | //返回处理结果给客户端 52 | outputStream = socket.getOutputStream(); 53 | byte[] bytes = response.getBytes(Charset.forName("UTF-8")); 54 | SocketClient.segmentWrite(bytes, outputStream); 55 | socket.shutdownOutput(); 56 | 57 | //关闭流 58 | SocketClient.close(socket,outputStream,isr,br,is); 59 | log.info("SocketService 服务端任务执行完成"); 60 | } catch (IOException e) { 61 | log.error("SocketService IOException", e); 62 | } catch (Exception e) { 63 | log.error("SocketService Exception", e); 64 | } finally { 65 | try { 66 | SocketClient.close(socket,outputStream,isr,br,is); 67 | } catch (IOException e) { 68 | log.error("SocketService IOException", e); 69 | } 70 | } 71 | } 72 | 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/demo/three/flow/FlowCenter.java: -------------------------------------------------------------------------------- 1 | package demo.three.flow; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.google.common.collect.ImmutableList; 5 | import com.google.common.collect.Lists; 6 | import com.google.common.collect.Maps; 7 | 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.util.CollectionUtils; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import javax.annotation.PostConstruct; 15 | 16 | import demo.three.flow.threadlocal.BeanFive; 17 | import demo.three.flow.threadlocal.BeanThree; 18 | import lombok.extern.slf4j.Slf4j; 19 | 20 | /** 21 | * FlowCenter 22 | * author wenhe 23 | * date 2019/8/11 24 | */ 25 | @Slf4j 26 | @Component 27 | public class FlowCenter { 28 | 29 | /** 30 | * flowMap 是共享变量,方便访问 31 | */ 32 | public static final Map>> flowMap 33 | = Maps.newConcurrentMap(); 34 | 35 | /** 36 | * PostConstruct 注解的意思就是 37 | * 在容器启动成功之后,初始化 flowMap 38 | */ 39 | @PostConstruct 40 | public void init() { 41 | // 初始化 flowMap mock 42 | Map> stageMap = flowMap.getOrDefault("flow1",Maps.newConcurrentMap()); 43 | for (StageEnum value : StageEnum.values()) { 44 | List domainAbilitys = stageMap.getOrDefault(value, Lists.newCopyOnWriteArrayList()); 45 | if(CollectionUtils.isEmpty(domainAbilitys)){ 46 | domainAbilitys.addAll(ImmutableList.of( 47 | ApplicationContextHelper.getBean(BeanOne.class), 48 | ApplicationContextHelper.getBean(BeanTwo.class) 49 | )); 50 | stageMap.put(value,domainAbilitys); 51 | } 52 | } 53 | flowMap.put("flow1",stageMap); 54 | 55 | // 初始化流程2 56 | Map> stageMap2 = flowMap.getOrDefault("flow2",Maps.newConcurrentMap()); 57 | List list2 = stageMap2.getOrDefault(StageEnum.PARAM_VALID,Lists.newArrayList()); 58 | list2.add(ApplicationContextHelper.getBean(BeanThree.class)); 59 | list2.add(ApplicationContextHelper.getBean(BeanFive.class)); 60 | stageMap2.put(StageEnum.PARAM_VALID,list2); 61 | flowMap.put("flow2",stageMap2); 62 | 63 | log.info("init success,flowMap is {}", JSON.toJSONString(flowMap)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/demo/two/LinkedHashMapDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import java.util.Iterator; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | /** 15 | * ArrayListDemo 16 | * author wenhe 17 | */ 18 | @Slf4j 19 | public class LinkedHashMapDemo { 20 | 21 | @Test 22 | public void testInsertOrder() { 23 | LinkedHashMap map = new LinkedHashMap() {{ 24 | put(10, 10); 25 | put(9, 9); 26 | put(20, 20); 27 | put(1, 1); 28 | }}; 29 | Assert.assertNotNull(map.get(9)); 30 | Assert.assertNotNull(map.get(20)); 31 | Assert.assertNotNull(map.get(9)); 32 | log.info(JSON.toJSONString(map)); 33 | 34 | } 35 | 36 | @Test 37 | public void testAccessOrder() { 38 | LinkedHashMap map = new LinkedHashMap(4,0.75f,true) { 39 | { 40 | put(10, 10); 41 | put(9, 9); 42 | put(20, 20); 43 | put(1, 1); 44 | } 45 | 46 | @Override 47 | protected boolean removeEldestEntry(Map.Entry eldest) { 48 | return size() > 3; 49 | } 50 | }; 51 | 52 | log.info("初始化:{}",JSON.toJSONString(map)); 53 | Assert.assertNotNull(map.get(9)); 54 | log.info("map.get(9):{}",JSON.toJSONString(map)); 55 | Assert.assertNotNull(map.get(20)); 56 | log.info("map.get(20):{}",JSON.toJSONString(map)); 57 | 58 | } 59 | 60 | @Test 61 | public void testIterator(){ 62 | LinkedHashMap map = new LinkedHashMap(4,0.75f,true) { 63 | { 64 | put(10, 10); 65 | put(9, 9); 66 | put(20, 20); 67 | put(1, 1); 68 | } 69 | }; 70 | 71 | log.info("迭代访问 start"); 72 | Iterator> iterator = map.entrySet().iterator(); 73 | while (iterator.hasNext()){ 74 | Map.Entry entry = iterator.next(); 75 | log.info(JSON.toJSONString(entry)); 76 | } 77 | log.info("迭代访问 end"); 78 | } 79 | 80 | public static void main(String[] args) { 81 | LinkedHashMap map = new LinkedHashMap(4,0.75f,true); 82 | map.put(1,1); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/CountDownLatchDemo.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | /** 8 | * 实现两个功能: 9 | * 1. 让一组线程在启动之后,先陷入等待状态,然后在某一时间被一起唤醒; 10 | * 2. 线程等待另外一组线程都执行完成之后,再继续执行。 11 | *author wenhe 12 | *date 2019/9/21 13 | */ 14 | public class CountDownLatchDemo { 15 | 16 | // 线程任务 17 | class Worker implements Runnable { 18 | // 实现功能 1 19 | private final CountDownLatch startSignal; 20 | // 实现功能 2 21 | private final CountDownLatch doneSignal; 22 | 23 | Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { 24 | this.startSignal = startSignal; 25 | this.doneSignal = doneSignal; 26 | } 27 | 28 | public void run() { 29 | try { 30 | System.out.println(Thread.currentThread().getName()+" begin"); 31 | // await 时有两点需要注意:await 时 state 不会发生变化,2:startSignal 的state初始化时 1,所以所有线程都会到同步队列中等待 32 | startSignal.await(); 33 | doWork(); 34 | // countDown 每次会使 state 减一,doneSignal 初始化为 9,countDown 前 8 次执行都会返回 false,执行第 9 次时,state 递减 35 | // 为 0,会 countDown 成功,表示所有子线程都执行完了,会释放 await 在 doneSignal 上的主线程 36 | doneSignal.countDown(); 37 | System.out.println(Thread.currentThread().getName()+" end"); 38 | } catch (InterruptedException ex) { 39 | } // return; 40 | } 41 | 42 | void doWork() throws InterruptedException { 43 | System.out.println(Thread.currentThread().getName()+"sleep 5s …………"); 44 | Thread.sleep(5000l); 45 | } 46 | } 47 | 48 | @Test 49 | public void test() throws InterruptedException { 50 | // state 初始化为 1 很关键,子线程是不断的 await,await 时 state 是不会变化的,并且发现 state 都是 1,所有线程都获取不到锁 51 | // 造成所有线程都到同步队列中去等待,当主线程执行 countDown 时,就会一起把等待的线程给释放掉 52 | CountDownLatch startSignal = new CountDownLatch(1); 53 | // state 初始化成 9,表示最大可有 9 个线程获得锁,主线程会执行 await 阻塞住,子线程不断的执行 countDown,当最后一个子线程 54 | // 执行 countDown 时,发现 state 被递减成 0 了,就能唤醒主线程 55 | CountDownLatch doneSignal = new CountDownLatch(9); 56 | 57 | for (int i = 0; i < 9; ++i) // create and start threads 58 | { 59 | new Thread(new Worker(startSignal, doneSignal)).start(); 60 | } 61 | System.out.println("main thread begin"); 62 | // 这行代码唤醒 9 个子线程,开始执行 63 | startSignal.countDown(); 64 | // 这行代码使主线程陷入沉睡,等待 9 个子线程执行完成之后才会继续执行 65 | doneSignal.await(); 66 | System.out.println("main thread end"); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/demo/three/CopyOnWriteArrayListDemo.java: -------------------------------------------------------------------------------- 1 | package demo.three; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | import java.util.Iterator; 7 | import java.util.concurrent.CopyOnWriteArrayList; 8 | import java.util.concurrent.locks.ReentrantLock; 9 | 10 | import lombok.Data; 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | /** 14 | * CopyOnWriteArrayListDemo 15 | *author wenhe 16 | *date 2019/8/5 17 | */ 18 | @Slf4j 19 | @Data 20 | public class CopyOnWriteArrayListDemo { 21 | 22 | final transient ReentrantLock lock = new ReentrantLock(); 23 | 24 | private transient volatile Object[] array; 25 | 26 | public void lockAndSleep(long millis){ 27 | final ReentrantLock lock = this.lock; 28 | //加锁 29 | log.info(Thread.currentThread()+"等待锁"); 30 | lock.lock(); 31 | log.info(Thread.currentThread()+"得到锁"); 32 | try { 33 | Thread.sleep(millis); 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | finally { 38 | log.info(Thread.currentThread()+"释放锁"); 39 | lock.unlock(); 40 | } 41 | } 42 | 43 | @Test 44 | public void testCopy() throws InterruptedException { 45 | new Thread(() -> { 46 | log.info(Thread.currentThread()+"开始运行"); 47 | lockAndSleep(1000*60*5); 48 | log.info(Thread.currentThread()+"结束运行"); 49 | }).start(); 50 | 51 | new Thread(() -> { 52 | log.info(Thread.currentThread()+"开始运行"); 53 | lockAndSleep(0); 54 | log.info(Thread.currentThread()+"结束运行"); 55 | }).start(); 56 | 57 | Thread.sleep(1000*60*8); 58 | } 59 | 60 | @Test 61 | public void testCopy2(){ 62 | Object[] objects = new Object[]{"nihoa","cdcd"}; 63 | setArray(objects); 64 | Object[] objects1 = getArray(); 65 | System.out.println(objects[1]); 66 | objects1[1] ="222"; 67 | System.out.println(objects[1]); 68 | } 69 | 70 | final Object[] getArray() { 71 | return array; 72 | } 73 | 74 | /** 75 | * Sets the array. 76 | */ 77 | final void setArray(Object[] a) { 78 | array = a; 79 | } 80 | 81 | 82 | @Test 83 | public void testIterator(){ 84 | CopyOnWriteArrayList list = new CopyOnWriteArrayList(); 85 | list.add("10"); 86 | list.add("20"); 87 | list.add("30"); 88 | Iterator iterator = list.iterator(); 89 | list.add("50"); 90 | iterator.next(); 91 | list.add("50"); 92 | } 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/ShareLock.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | import java.io.Serializable; 3 | import java.util.concurrent.locks.AbstractQueuedSynchronizer; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * 非公平共享锁 9 | *author wenhe 10 | *date 2019/9/28 11 | */ 12 | @Slf4j 13 | public class ShareLock implements Serializable{ 14 | 15 | private final Sync sync; 16 | // 用于确保不能超过最大值 17 | private final int maxCount; 18 | 19 | /** 20 | * 初始化时给同步器 sync 赋值 21 | * count 代表可以获得共享锁的最大值 22 | */ 23 | public ShareLock(int count) { 24 | this.sync = new Sync(count); 25 | maxCount = count; 26 | } 27 | 28 | /** 29 | * 获得锁 30 | * @return 31 | */ 32 | public boolean lock(){ 33 | return sync.acquireByShared(1); 34 | } 35 | 36 | /** 37 | * 失去锁 38 | * @return 39 | */ 40 | public boolean unLock(){ 41 | return sync.releaseShared(1); 42 | } 43 | 44 | class Sync extends AbstractQueuedSynchronizer { 45 | 46 | // 表示最多有 count 个共享锁可以获得 47 | public Sync(int count) { 48 | setState(count); 49 | } 50 | 51 | // 获得 i 个锁 52 | public boolean acquireByShared(int i) { 53 | // 自旋保证 CAS 一定可以成功 54 | for(;;){ 55 | if(i<=0){ 56 | return false; 57 | } 58 | int state = getState(); 59 | // 如果没有锁可以获得,直接返回 false 60 | if(state <=0 ){ 61 | return false; 62 | } 63 | int expectState = state - i; 64 | // 如果要得到的锁不够了,直接返回 false 65 | if(expectState < 0 ){ 66 | return false; 67 | } 68 | // CAS 尝试得到锁,CAS 成功获得锁,失败继续 for 循环 69 | if(compareAndSetState(state,expectState)){ 70 | return true; 71 | } 72 | } 73 | } 74 | 75 | // 释放 i 个锁 76 | @Override 77 | protected boolean tryReleaseShared(int arg) { 78 | for(;;){ 79 | if(arg<=0){ 80 | return false; 81 | } 82 | int state = getState(); 83 | int expectState = state + arg; 84 | // 超过了 int 的最大值 85 | if(expectState < 0 || expectState > maxCount){ 86 | log.error("state 超过预期,当前 state is {},计算出的 state is {}",state 87 | ,expectState); 88 | return false; 89 | } 90 | if(compareAndSetState(state, expectState)){ 91 | return true; 92 | } 93 | } 94 | } 95 | } 96 | 97 | 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/demo/five/FutureTaskDemo.java: -------------------------------------------------------------------------------- 1 | package demo.five; 2 | import java.util.concurrent.LinkedBlockingQueue; 3 | import java.util.concurrent.ThreadPoolExecutor; 4 | import java.util.concurrent.Callable; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.junit.Test; 8 | 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.FutureTask; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import lombok.extern.slf4j.Slf4j; 14 | 15 | @Slf4j 16 | public class FutureTaskDemo { 17 | 18 | @Test 19 | public void initCallable() throws ExecutionException, InterruptedException { 20 | FutureTask futureTask = new FutureTask(new Callable () { 21 | @Override 22 | public String call() throws Exception { 23 | Thread.sleep(3000); 24 | return "nihao"; 25 | } 26 | }); 27 | futureTask.run(); 28 | log.info("get ing"); 29 | String result = (String) futureTask.get(); 30 | log.info("拿到值了,为 {}",result); 31 | } 32 | 33 | @Test 34 | public void initRunnable() throws ExecutionException, InterruptedException { 35 | FutureTask futureTask = new FutureTask(new Runnable() { 36 | @Override 37 | public void run() { 38 | log.info("{} is run",Thread.currentThread().getName()); 39 | } 40 | }, null); 41 | futureTask.run(); 42 | String result = futureTask.get(); 43 | log.info("run end,result is {}",result); 44 | } 45 | 46 | @Test 47 | public void testGet() throws ExecutionException, InterruptedException { 48 | ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, 49 | new LinkedBlockingQueue<>()); 50 | FutureTask futureTask = new FutureTask(new Callable () { 51 | @Override 52 | public String call() throws Exception { 53 | Thread.sleep(3000); 54 | return "我是子线程"+Thread.currentThread().getName(); 55 | } 56 | }); 57 | executor.submit(futureTask); 58 | String result = (String) futureTask.get(); 59 | log.info("result is {}",result); 60 | } 61 | 62 | @Test 63 | public void testThreadByCallable() throws ExecutionException, InterruptedException { 64 | FutureTask futureTask = new FutureTask(new Callable () { 65 | @Override 66 | public String call() throws Exception { 67 | Thread.sleep(3000); 68 | String result = "我是子线程"+Thread.currentThread().getName(); 69 | log.info("子线程正在运行:{}",Thread.currentThread().getName()); 70 | return result; 71 | } 72 | }); 73 | new Thread(futureTask).start(); 74 | log.info("返回的结果是 {}",futureTask.get()); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/test.groovy: -------------------------------------------------------------------------------- 1 | package demo.sixth 2 | 3 | import com.alibaba.fastjson.JSON 4 | 5 | class ScriptTest { 6 | 7 | def static main(args) { 8 | def dataStr = '{"auto":"1","img":"{}","extension":"{\\"source\\":{\\"fromApp\\":\\"trade-core\\",\\"source\\":0},\\"operator\\":{\\"operatorId\\":12303369,\\"role\\":\\"buyer\\"},\\"extraMap\\":{}}","buyer_tax_info":"{\\"taxpayerId\\":\\"91110106MA003K614D\\",\\"userName\\":\\"中质国认(北京)计量科学研究院\\",\\"raiseType\\":\\"enterprise\\"}","sms_setting":"{\\"emailList\\":[\\"Sophiazuozuo@163.com\\"]}","invoice_asset_id":"20190426180114011017","created_at":"2019-09-25 06:44:53","red_invoice":"0","kdt_id":"13328377","updated_at":"2019-09-25 06:44:53","sharding_id":"22","biz_no":"E20190901174429002200005","check_code":"","invoice_id":"20190925064453010022","invoice_success_date":"2010-01-01 00:00:00","invoice_type":"1","id":"1541314308421451777","invoice_detail_type":"itemDetail","error_msg":"","expires_date":"2019-09-25 06:44:53","invoice_no":"","blue_invoice_id":"","invoice_tag":"16","version":"1569365093884","invoice_code":"","pdf":"{}","goods_list_file":"{}","invalid":"0","status":"1"}' 9 | def data = JSON.parse(dataStr) 10 | exec(data) 11 | } 12 | 13 | private static threadlcoalFormat = ThreadLocal.withInitial({return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")} as java.util.function.Supplier) 14 | 15 | 16 | def static exec(data) { 17 | data.invoice_status_code = data.status 18 | data.invoice_status_type_code = data.red_invoice 19 | data.create_time = threadlcoalFormat.get().parse(data.created_at.toString()).getTime()/1000L 20 | 21 | def jsonSlurper = new groovy.json.JsonSlurper() 22 | data.operator = jsonSlurper.parseText(data.extension)?.operator?.role 23 | data.operator_id = jsonSlurper.parseText(data.extension)?.operator?.operatorId 24 | data.invoice_file = data.pdf 25 | data.is_red_freshed = data.invoice_status_type_code.toInteger() == 0 && data.invoice_status_code.toInteger() == 40 26 | if (null == data.biz_no || "".equals(data.biz_no)) { 27 | data.order_no = "" 28 | data.order_shard_id = 1 29 | } else { 30 | data.order_no = data.biz_no 31 | data.order_shard_id = data.order_no.substring(15, 19).toInteger() 32 | } 33 | data.source = jsonSlurper.parseText(data.extension)?.source?.source 34 | def parent_kdt_id = jsonSlurper.parseText(data.extension) != null && jsonSlurper.parseText(data.extension)?.extraMap != null ? 35 | jsonSlurper.parseText(data.extension)?.extraMap.RETAIL_PARENT_KDT_ID : null 36 | data.head_kdt_id = parent_kdt_id != null ? Long.parseLong(parent_kdt_id) : data.kdt_id 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/demo/sixth/BatchRefundDemo.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | import java.util.concurrent.Callable; 3 | 4 | import com.google.common.collect.Lists; 5 | 6 | import org.junit.Test; 7 | 8 | import java.util.List; 9 | import java.util.concurrent.CountDownLatch; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Future; 13 | import java.util.concurrent.LinkedBlockingQueue; 14 | import java.util.concurrent.ThreadPoolExecutor; 15 | import java.util.concurrent.TimeUnit; 16 | import java.util.concurrent.TimeoutException; 17 | import java.util.stream.Collectors; 18 | 19 | import lombok.extern.slf4j.Slf4j; 20 | 21 | /** 22 | * 批量退款场景 23 | * 双 11,小明在网上买了 50 个商品,一个订单,第二天小明觉得自己买了很多不需要的东西,挑选了一下,一共了 30 个商品是自己暂时不需要的 24 | * 于是小明想把 30 个商品给推掉,于是在页面上选择了这 30 个商品,发起了批量退款 25 | */ 26 | @Slf4j 27 | public class BatchRefundDemo { 28 | 29 | public static final ExecutorService EXECUTOR_SERVICE = 30 | new ThreadPoolExecutor(10, 10, 0L, 31 | TimeUnit.MILLISECONDS, 32 | new LinkedBlockingQueue<>(20)); 33 | @Test 34 | public void batchRefund() throws InterruptedException { 35 | CountDownLatch countDownLatch = new CountDownLatch(30); 36 | RefundDemo refundDemo = new RefundDemo(); 37 | 38 | // 准备 30 个商品 39 | List items = Lists.newArrayListWithCapacity(30); 40 | for (int i = 0; i < 30; i++) { 41 | items.add(Long.valueOf(i+"")); 42 | } 43 | 44 | long begin = System.currentTimeMillis(); 45 | // 准备开始批量退款 46 | List futures = Lists.newArrayListWithCapacity(30); 47 | for (Long item : items) { 48 | Future future = EXECUTOR_SERVICE.submit(new Callable() { 49 | @Override 50 | public Boolean call() throws Exception { 51 | boolean result = refundDemo.refundByItem(item); 52 | countDownLatch.countDown(); 53 | return result; 54 | } 55 | }); 56 | futures.add(future); 57 | } 58 | 59 | log.info("30 个商品已经在退款中"); 60 | countDownLatch.await(); 61 | log.info("30 个商品已经退款完成"); 62 | List result = futures.stream().map(fu-> { 63 | try { 64 | return (Boolean) fu.get(1,TimeUnit.MILLISECONDS); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(); 67 | } catch (ExecutionException e) { 68 | e.printStackTrace(); 69 | } catch (TimeoutException e) { 70 | e.printStackTrace(); 71 | } 72 | return false; 73 | }).collect(Collectors.toList()); 74 | long success = result.stream().filter(r->r.equals(true)).count(); 75 | log.info("执行结果成功{},失败{}",success,result.size()-success); 76 | log.info("耗时{}",System.currentTimeMillis()-begin); 77 | 78 | long begin1 = System.currentTimeMillis(); 79 | for (Long item : items) { 80 | refundDemo.refundByItem(item); 81 | } 82 | log.info("for 循环单个退款耗时{}",System.currentTimeMillis()-begin1); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/demo/two/ArraysDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.google.common.collect.ImmutableList; 5 | 6 | import org.junit.Test; 7 | 8 | import java.util.Arrays; 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | import java.util.Comparator; 12 | import java.util.List; 13 | 14 | import lombok.Data; 15 | import lombok.extern.slf4j.Slf4j; 16 | 17 | /** 18 | * ArraysDemo 19 | *author wenhe 20 | *date 2019/8/3 21 | */ 22 | @Slf4j 23 | public class ArraysDemo { 24 | 25 | @Test 26 | public void testSort(){ 27 | List list = ImmutableList.of( 28 | new SortDTO("300"), 29 | new SortDTO("50"), 30 | new SortDTO("200"), 31 | new SortDTO("220") 32 | ); 33 | // 我们先把数组的大小初始化成 list 的大小 34 | SortDTO[] array = new SortDTO[list.size()]; 35 | list.toArray(array); 36 | 37 | log.info("排序之前:{}", JSON.toJSONString(array)); 38 | Arrays.sort(array, Comparator.comparing(SortDTO::getSortTarget)); 39 | log.info("排序之后:{}", JSON.toJSONString(array)); 40 | } 41 | 42 | @Test 43 | public void testBinarySearch(){ 44 | List list = ImmutableList.of( 45 | new SortDTO("300"), 46 | new SortDTO("50"), 47 | new SortDTO("200"), 48 | new SortDTO("220") 49 | ); 50 | 51 | SortDTO[] array = new SortDTO[list.size()]; 52 | list.toArray(array); 53 | 54 | log.info("搜索之前:{}", JSON.toJSONString(array)); 55 | Arrays.sort(array, Comparator.comparing(SortDTO::getSortTarget)); 56 | log.info("先排序,结果为:{}", JSON.toJSONString(array)); 57 | int index = Arrays.binarySearch(array, new SortDTO("200"), 58 | Comparator.comparing(SortDTO::getSortTarget)); 59 | if(index<0){ 60 | throw new RuntimeException("没有找到 200"); 61 | } 62 | log.info("搜索结果:{}", JSON.toJSONString(array[index])); 63 | } 64 | 65 | @Data 66 | class SortDTO { 67 | 68 | private String sortTarget; 69 | 70 | public SortDTO(String sortTarget) { 71 | this.sortTarget = sortTarget; 72 | } 73 | } 74 | 75 | class SortDTO1 implements Comparable { 76 | 77 | private String sortTarget; 78 | 79 | public SortDTO1(String sortTarget) { 80 | this.sortTarget = sortTarget; 81 | } 82 | 83 | @Override 84 | public int compareTo(SortDTO1 o) { 85 | return o.sortTarget.compareTo(sortTarget); 86 | } 87 | } 88 | 89 | @Test 90 | public void testMax() { 91 | Collection list = ImmutableList.of( 92 | new SortDTO1("300"), 93 | new SortDTO1("50"), 94 | new SortDTO1("200"), 95 | new SortDTO1("220") 96 | ); 97 | Collections.max(list); 98 | } 99 | 100 | @Test 101 | public void testSearch(){ 102 | //0~10 103 | System.out.println("(0 + 10-1) >>> 1:"+((0 + 10-1) >>> 1)); 104 | System.out.println("(0 + 11-1) >>> 1:"+((0 + 11-1) >>> 1)); 105 | System.out.println("(1 + 11-1) >>> 1:"+((1 + 11-1) >>> 1)); 106 | System.out.println("(1 + 10-1) >>> 1:"+((1 + 10-1) >>> 1)); 107 | } 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/demo/four/DIYQueue.java: -------------------------------------------------------------------------------- 1 | package demo.four; 2 | import java.util.concurrent.TimeUnit; 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | /** 9 | * 自定义队列 10 | *author wenhe 11 | *date 2019/9/1 12 | */ 13 | @Slf4j 14 | public class DIYQueue implements Queue{ 15 | 16 | /** 17 | * 队列头 18 | */ 19 | private volatile Node head; 20 | 21 | /** 22 | * 队列尾 23 | */ 24 | private volatile Node tail; 25 | 26 | /** 27 | * 自定义队列元素 28 | */ 29 | class DIYNode extends Node{ 30 | public DIYNode(T item) { 31 | super(item); 32 | } 33 | } 34 | 35 | /** 36 | * 队列的大小 37 | */ 38 | private AtomicInteger size = new AtomicInteger(0); 39 | 40 | /** 41 | * 容量 42 | */ 43 | private final Integer capacity; 44 | 45 | /** 46 | * 放数据锁 47 | */ 48 | private ReentrantLock putLock = new ReentrantLock(); 49 | 50 | /** 51 | * 拿数据锁 52 | */ 53 | private ReentrantLock takeLock = new ReentrantLock(); 54 | 55 | /** 56 | * 无参数构造器,默认最大容量是 Integer.MAX_VALUE 57 | */ 58 | public DIYQueue() { 59 | capacity = Integer.MAX_VALUE; 60 | head = tail = new DIYNode(null); 61 | } 62 | 63 | /** 64 | * 有参数构造器,可以设定容量的大小 65 | * @param capacity 66 | */ 67 | public DIYQueue(Integer capacity) { 68 | if(null == capacity || capacity < 0){ 69 | throw new IllegalArgumentException(); 70 | } 71 | this.capacity = capacity; 72 | head = tail = new DIYNode(null); 73 | } 74 | 75 | @Override 76 | public boolean put(T item) { 77 | if(null == item){ 78 | return false; 79 | } 80 | try{ 81 | // 尝试加锁 82 | boolean lockSuccess = putLock.tryLock(300, TimeUnit.MILLISECONDS); 83 | if(!lockSuccess){ 84 | return false; 85 | } 86 | // 校验队列大小 87 | if(size.get() >= capacity){ 88 | log.info("queue is full"); 89 | return false; 90 | } 91 | // 追加到队尾 92 | tail = tail.next = new DIYNode(item); 93 | size.incrementAndGet(); 94 | return true; 95 | } catch (InterruptedException e){ 96 | log.info("put error", e); 97 | return false; 98 | } catch(Exception e){ 99 | log.error("put error", e); 100 | return false; 101 | } finally { 102 | putLock.unlock(); 103 | } 104 | } 105 | 106 | @Override 107 | public T take() { 108 | // 队列是空的 109 | if(size.get() == 0){ 110 | return null; 111 | } 112 | try { 113 | // 拿数据我们设置的超时时间更短 114 | boolean lockSuccess = takeLock.tryLock(200,TimeUnit.MILLISECONDS); 115 | if(!lockSuccess){ 116 | throw new RuntimeException("加锁失败"); 117 | } 118 | // 把头结点的下一个元素拿出来 119 | Node expectHead = head.next; 120 | // 把头结点的值拿出来 121 | T result = head.item; 122 | // 把头结点的值置为 null,帮助 gc 123 | head.item = null; 124 | // 重新设置头结点的值 125 | head = (DIYNode) expectHead; 126 | size.decrementAndGet(); 127 | // 返回头结点的值 128 | return result; 129 | } catch (InterruptedException e) { 130 | log.info(" tryLock 200 timeOut",e); 131 | } catch (Exception e) { 132 | log.info(" take error ",e); 133 | } finally { 134 | takeLock.unlock(); 135 | } 136 | return null; 137 | } 138 | 139 | 140 | 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/demo/ninth/socket/SocketServiceStart.java: -------------------------------------------------------------------------------- 1 | package demo.ninth.socket; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.net.InetAddress; 8 | import java.net.InetSocketAddress; 9 | import java.net.ServerSocket; 10 | import java.net.Socket; 11 | import java.nio.charset.Charset; 12 | import java.util.concurrent.LinkedBlockingQueue; 13 | import java.util.concurrent.ThreadPoolExecutor; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import lombok.extern.slf4j.Slf4j; 17 | 18 | /** 19 | * SocketService 20 | * author wenhe 21 | * date 2019/10/17 22 | */ 23 | @Slf4j 24 | public class SocketServiceStart { 25 | 26 | /** 27 | * 服务端的线程池,两个作用 28 | * 1:让服务端的任务可以异步执行 29 | * 2:管理可同时处理的服务端的请求数 30 | */ 31 | private static final ThreadPoolExecutor collectPoll = new ThreadPoolExecutor(4, 4, 32 | 365L, 33 | TimeUnit.DAYS, 34 | new LinkedBlockingQueue<>( 35 | 1)); 36 | 37 | @Test 38 | public void test(){ 39 | start(); 40 | } 41 | 42 | /** 43 | * 启动服务端 44 | */ 45 | public static final void start() { 46 | log.info("SocketServiceStart 服务端开始启动"); 47 | try { 48 | // backlog serviceSocket处理阻塞时,客户端最大的可创建连接数,超过客户端连接不上 49 | // 当线程池能力处理满了之后,我们希望尽量阻塞客户端的连接 50 | // ServerSocket serverSocket = new ServerSocket(7007,1,null); 51 | // 初始化服务端 52 | ServerSocket serverSocket = new ServerSocket(); 53 | serverSocket.setReuseAddress(true); 54 | // serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), 80)); 55 | serverSocket.bind(new InetSocketAddress("localhost", 7007)); 56 | log.info("SocketServiceStart 服务端启动成功"); 57 | // 自旋,让客户端一直在取客户端的请求,如果客户端暂时没有请求,会一直阻塞 58 | while (true) { 59 | // 接受客户端的请求 60 | Socket socket = serverSocket.accept(); 61 | 62 | // 如果队列中有数据了,说明服务端已经到了并发处理的极限了,此时需要返回客户端有意义的信息 63 | if (collectPoll.getQueue().size() >= 1) { 64 | log.info("SocketServiceStart 服务端处理能力到顶,需要控制客户端的请求"); 65 | //返回处理结果给客户端 66 | rejectRequest(socket); 67 | continue; 68 | } 69 | try { 70 | // 异步处理客户端提交上来的任务 71 | collectPoll.submit(new SocketService(socket)); 72 | } catch (Exception e) { 73 | socket.close(); 74 | } 75 | } 76 | } catch (Exception e) { 77 | log.error("SocketServiceStart - start error", e); 78 | throw new RuntimeException(e); 79 | } catch (Throwable e) { 80 | log.error("SocketServiceStart - start error", e); 81 | throw new RuntimeException(e); 82 | } 83 | } 84 | 85 | public static void rejectRequest(Socket socket) throws IOException { 86 | OutputStream outputStream = null; 87 | try{ 88 | outputStream = socket.getOutputStream(); 89 | byte[] bytes = "服务器太忙了,请稍后重试~".getBytes(Charset.forName("UTF-8")); 90 | SocketClient.segmentWrite(bytes, outputStream); 91 | socket.shutdownOutput(); 92 | }finally { 93 | //关闭流 94 | SocketClient.close(socket,outputStream,null,null,null); 95 | } 96 | } 97 | 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/demo/four/DelayQueueDemo.java: -------------------------------------------------------------------------------- 1 | package demo.four; 2 | import com.google.common.collect.ImmutableList; 3 | 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.concurrent.ArrayBlockingQueue; 7 | 8 | import org.junit.Test; 9 | 10 | import java.util.concurrent.BlockingQueue; 11 | import java.util.concurrent.DelayQueue; 12 | import java.util.concurrent.Delayed; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import lombok.Data; 16 | import lombok.extern.slf4j.Slf4j; 17 | 18 | /** 19 | * DelayQueueDemo 20 | * author wenhe 21 | * date 2019/8/19 22 | */ 23 | @Slf4j 24 | public class DelayQueueDemo { 25 | 26 | static class Product implements Runnable { 27 | 28 | private final BlockingQueue queue; 29 | 30 | public Product(BlockingQueue queue) { 31 | this.queue = queue; 32 | } 33 | 34 | @Override 35 | public void run() { 36 | try { 37 | log.info("begin put"); 38 | long beginTime = System.currentTimeMillis(); 39 | queue.put(new DelayedDTO(System.currentTimeMillis() + 2000L,beginTime));//延迟 2 秒执行 40 | queue.put(new DelayedDTO(System.currentTimeMillis() + 5000L,beginTime));//延迟 5 秒执行 41 | queue.put(new DelayedDTO(System.currentTimeMillis() + 1000L * 10,beginTime));//延迟 10 秒执行 42 | log.info("end put"); 43 | } catch (InterruptedException e) { 44 | log.error("" + e); 45 | } 46 | } 47 | } 48 | 49 | static class Consumer implements Runnable { 50 | 51 | private final BlockingQueue queue; 52 | 53 | public Consumer(BlockingQueue queue) { 54 | this.queue = queue; 55 | } 56 | 57 | @Override 58 | public void run() { 59 | try { 60 | log.info("Consumer begin"); 61 | ((DelayedDTO) queue.take()).run(); 62 | ((DelayedDTO) queue.take()).run(); 63 | ((DelayedDTO) queue.take()).run(); 64 | log.info("Consumer end"); 65 | } catch (InterruptedException e) { 66 | log.error("" + e); 67 | } 68 | } 69 | } 70 | 71 | @Data 72 | static class DelayedDTO implements Delayed { 73 | Long s; 74 | Long beginTime; 75 | public DelayedDTO(Long s,Long beginTime) { 76 | this.s = s; 77 | this.beginTime =beginTime; 78 | } 79 | 80 | @Override 81 | public long getDelay(TimeUnit unit) { 82 | return unit.convert(s - System.currentTimeMillis(), TimeUnit.MILLISECONDS); 83 | } 84 | 85 | @Override 86 | public int compareTo(Delayed o) { 87 | return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); 88 | } 89 | 90 | public void run(){ 91 | log.info("延迟了{}秒钟才执行",(System.currentTimeMillis() - beginTime)/1000); 92 | } 93 | } 94 | 95 | public static void main(String[] args) throws InterruptedException { 96 | BlockingQueue q = new DelayQueue(); 97 | DelayQueueDemo.Product p = new DelayQueueDemo.Product(q); 98 | DelayQueueDemo.Consumer c = new DelayQueueDemo.Consumer(q); 99 | // new Thread(c).start(); 100 | // new Thread(p).start(); 101 | 102 | log.info("1,{}",(1 - 1) >>> 1); 103 | log.info("2,{}",(2 - 1) >>> 1); 104 | log.info("10,{}",(10 - 1) >>> 1); 105 | log.info("15,{}",(15 - 1) >>> 1); 106 | log.info("200,{}",(200 - 1) >>> 1); 107 | } 108 | 109 | @Test 110 | public void testInit(){ 111 | List list = ImmutableList.of("a","b","c"); 112 | ArrayBlockingQueue q = 113 | new ArrayBlockingQueue(1,true,list); 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/demo/one/StringDemo.java: -------------------------------------------------------------------------------- 1 | package demo.one; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.google.common.base.Joiner; 5 | import com.google.common.base.Splitter; 6 | import com.google.common.collect.Lists; 7 | 8 | import org.junit.Test; 9 | 10 | import java.io.UnsupportedEncodingException; 11 | import java.util.List; 12 | 13 | import lombok.extern.slf4j.Slf4j; 14 | 15 | /** 16 | * StringDemo 17 | *author wenhe 18 | *date 2019/7/28 19 | */ 20 | @Slf4j 21 | public class StringDemo { 22 | 23 | @Test 24 | public void testFinal(){ 25 | String s ="hello"; 26 | s ="world"; 27 | log.info(s); 28 | } 29 | 30 | @Test 31 | public void testGibberish() throws UnsupportedEncodingException { 32 | String str ="nihao 你好 喬亂"; 33 | byte[] bytes = str.getBytes("ISO-8859-1"); 34 | String s2 = new String(bytes,"ISO-8859-1"); 35 | log.info(s2); 36 | } 37 | 38 | @Test 39 | public void testReplace(){ 40 | String str ="hello word !!"; 41 | log.info("替换之前 :{}",str); 42 | str = str.replace('l','d'); 43 | log.info("替换所有字符 :{}",str); 44 | str = str.replaceAll("d","l"); 45 | log.info("替换全部 :{}",str); 46 | str = str.replaceFirst("l",""); 47 | log.info("替换第一个 :{}",str); 48 | } 49 | 50 | @Test 51 | public void testSplit(){ 52 | String s ="boo:and:foo"; 53 | log.info("s.split(\":\") 结果:{}", JSON.toJSONString( s.split(":") )); 54 | log.info("s.split(\":\",2) 结果:{}", JSON.toJSONString( s.split(":",2) )); 55 | log.info("s.split(\":\",5) 结果:{}", JSON.toJSONString( s.split(":",5) )); 56 | log.info("s.split(\":\",-2) 结果:{}", JSON.toJSONString( s.split(":",-2) )); 57 | log.info("s.split(\"o\") 结果:{}", JSON.toJSONString( s.split("o") )); 58 | log.info("s.split(\"o\",2) 结果:{}", JSON.toJSONString( s.split("o",2) )); 59 | 60 | 61 | String a1 =",a, , b c ,null"; 62 | log.info("a.split(\",\") 结果:{}", JSON.toJSONString( a1.split(",") )); 63 | 64 | String a =",a, , b c ,"; 65 | List list = Splitter.on(',') 66 | .trimResults()// 去掉空格 67 | .omitEmptyStrings()// 去掉空值 68 | .splitToList(a); 69 | log.info("Guava 去掉空格的分割方法:{}",JSON.toJSONString(list)); 70 | } 71 | 72 | @Test 73 | public void testJoin(){ 74 | String s ="hello"; 75 | String s1 ="china"; 76 | s.replace("nihao","sss"); 77 | // log.info(s.join(",",s1).join(",","null")); 78 | 79 | 80 | // 依次 join 多个字符串 81 | Joiner joiner = Joiner.on(",").skipNulls(); 82 | String result = joiner.join("hello",null,"china"); 83 | log.info("依次 join 多个字符串:{}",result); 84 | 85 | List list = Lists.newArrayList(new String[]{"hello","china",null}); 86 | log.info("自动删除 list 中空值:{}",joiner.join(list)); 87 | 88 | String r1 = String.join(",",list); 89 | // log.info("结果为:{}",r1); 90 | } 91 | 92 | @Test 93 | public void testLong128(){ 94 | Long.valueOf(128); 95 | Long.valueOf(129); 96 | } 97 | 98 | @Test 99 | public void testReplaceAndAll(){ 100 | StringBuffer strb = new StringBuffer(); 101 | int size =1000; 102 | for (int i = 0; i < size; i++) 103 | strb.append("o"); 104 | String s = strb.toString(); 105 | String s1 = strb.toString(); 106 | long begin = System.currentTimeMillis(); 107 | s.replace('o','l'); 108 | log.info("循环{}次, replace 耗时{}",size, (System.currentTimeMillis() - begin)); 109 | begin = System.currentTimeMillis(); 110 | s1.replaceAll("o","l"); 111 | log.info("循环{}次, replace 耗时{}",size, (System.currentTimeMillis() - begin)); 112 | } 113 | 114 | @Test 115 | public void testSplit2(){ 116 | String s =" i "; 117 | char ch = '-'; 118 | String[] sArrt = s.split("i",1); 119 | System.out.println(sArrt); 120 | } 121 | 122 | @Test 123 | public void test(){ 124 | new String("123123").substring(1,3); 125 | String a ="123"; 126 | String s ="123"; 127 | System.out.println(a==s); 128 | System.out.println(a==s); 129 | System.out.println("123"=="123"); 130 | } 131 | 132 | 133 | } 134 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.java 8 | java-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 1.8 13 | 4.3.5.RELEASE 14 | 15 | 16 | 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | 1.16.20 22 | 23 | 24 | 25 | org.apache.commons 26 | commons-lang3 27 | 3.4 28 | 29 | 30 | 31 | com.alibaba 32 | fastjson 33 | 1.2.47 34 | 35 | 36 | 37 | 38 | org.slf4j 39 | slf4j-api 40 | 1.7.9 41 | 42 | 43 | ch.qos.logback 44 | logback-core 45 | 1.2.3 46 | 47 | 48 | ch.qos.logback 49 | logback-classic 50 | 1.2.3 51 | 52 | 53 | 54 | 55 | junit 56 | junit 57 | 4.12 58 | 59 | 60 | 61 | com.google.guava 62 | guava 63 | 23.0 64 | 65 | 66 | 67 | commons-collections 68 | commons-collections 69 | 3.2.2 70 | 71 | 72 | 73 | 74 | org.springframework 75 | spring-core 76 | ${spring-version} 77 | 78 | 79 | org.springframework 80 | spring-beans 81 | ${spring-version} 82 | 83 | 84 | org.springframework 85 | spring-aop 86 | ${spring-version} 87 | 88 | 89 | org.springframework 90 | spring-context 91 | ${spring-version} 92 | 93 | 94 | org.springframework 95 | spring-context-support 96 | ${spring-version} 97 | 98 | 99 | 100 | org.springframework 101 | spring-tx 102 | 4.3.17.RELEASE 103 | 104 | 105 | 106 | 107 | 108 | org.springframework.boot 109 | spring-boot-starter-web 110 | 1.5.8.RELEASE 111 | 112 | 113 | org.codehaus.groovy 114 | groovy-all 115 | 2.4.15 116 | compile 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-compiler-plugin 127 | 128 | 1.8 129 | 1.8 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/main/java/demo/ninth/socket/SocketClient.java: -------------------------------------------------------------------------------- 1 | package demo.ninth.socket; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.junit.Test; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.OutputStream; 11 | import java.net.ConnectException; 12 | import java.net.InetSocketAddress; 13 | import java.net.Socket; 14 | import java.net.SocketException; 15 | import java.nio.charset.Charset; 16 | import java.util.concurrent.LinkedBlockingQueue; 17 | import java.util.concurrent.ThreadPoolExecutor; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | import lombok.extern.slf4j.Slf4j; 21 | 22 | /** 23 | * SocketClient 24 | * author wenhe 25 | * 客户端请求数据的工具类 26 | * date 2019/10/17 27 | */ 28 | @Slf4j 29 | public class SocketClient { 30 | 31 | 32 | private static final Integer SIZE = 1024; 33 | 34 | private static final ThreadPoolExecutor socketPoll = new ThreadPoolExecutor(50, 50, 35 | 365L, 36 | TimeUnit.DAYS, 37 | new LinkedBlockingQueue<>( 38 | 400)); 39 | 40 | @Test 41 | public void test() throws InterruptedException { 42 | // 模拟客户端同时向服务端发送 6 条消息 43 | for (int i = 0; i < 6; i++) { 44 | socketPoll.submit(() -> { 45 | send("localhost", 7007, "nihao"); 46 | }); 47 | } 48 | Thread.sleep(1000000000); 49 | } 50 | /** 51 | * 发送tcp 52 | * 53 | * @param domainName 域名 54 | * @param port 端口 55 | * @param content 发送内容 56 | */ 57 | public static String send(String domainName, int port, String content) { 58 | log.info("客户端开始运行"); 59 | Socket socket = null; 60 | OutputStream outputStream = null; 61 | InputStreamReader isr = null; 62 | BufferedReader br = null; 63 | InputStream is = null; 64 | StringBuffer response = null; 65 | try { 66 | if (StringUtils.isBlank(domainName)) { 67 | return null; 68 | } 69 | // 无参构造器初始化 Socket,默认底层协议是 TCP 70 | socket = new Socket(); 71 | socket.setReuseAddress(true); 72 | // 客户端准备连接服务端,设置超时时间 10 秒 73 | socket.connect(new InetSocketAddress(domainName, port), 10000); 74 | log.info("TCPClient 成功和服务端建立连接"); 75 | // 准备发送消息给服务端 76 | outputStream = socket.getOutputStream(); 77 | // 设置 UTF 编码,防止乱码 78 | byte[] bytes = content.getBytes(Charset.forName("UTF-8")); 79 | // 输出字节码 80 | segmentWrite(bytes, outputStream); 81 | // 关闭输出 82 | socket.shutdownOutput(); 83 | log.info("TCPClient 发送内容为 {}",content); 84 | 85 | // 等待服务端的返回 86 | socket.setSoTimeout(50000);//50秒还没有得到数据,直接断开连接 87 | // 得到服务端的返回流 88 | is = socket.getInputStream(); 89 | isr = new InputStreamReader(is); 90 | br = new BufferedReader(isr); 91 | // 从流中读取返回值 92 | response = segmentRead(br); 93 | // 关闭输入流 94 | socket.shutdownInput(); 95 | 96 | //关闭各种流和套接字 97 | close(socket, outputStream, isr, br, is); 98 | log.info("TCPClient 接受到服务端返回的内容为 {}",response); 99 | return response.toString(); 100 | } catch (ConnectException e) { 101 | log.error("TCPClient-send socket连接失败", e); 102 | throw new RuntimeException("socket连接失败"); 103 | } catch (Exception e) { 104 | log.error("TCPClient-send unkown errror", e); 105 | throw new RuntimeException("socket连接失败"); 106 | } finally { 107 | try { 108 | close(socket, outputStream, isr, br, is); 109 | } catch (Exception e) { 110 | // do nothing 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * 关闭各种流 117 | * 118 | * @param socket 119 | * @param outputStream 120 | * @param isr 121 | * @param br 122 | * @param is 123 | * @throws IOException 124 | */ 125 | public static void close(Socket socket, OutputStream outputStream, InputStreamReader isr, 126 | BufferedReader br, InputStream is) throws IOException { 127 | if (null != socket && !socket.isClosed()) { 128 | try { 129 | socket.shutdownOutput(); 130 | } catch (Exception e) { 131 | } 132 | try { 133 | socket.shutdownInput(); 134 | } catch (Exception e) { 135 | } 136 | try { 137 | socket.close(); 138 | } catch (Exception e) { 139 | } 140 | } 141 | if (null != outputStream) { 142 | outputStream.close(); 143 | } 144 | if (null != br) { 145 | br.close(); 146 | } 147 | if (null != isr) { 148 | isr.close(); 149 | } 150 | if (null != is) { 151 | is.close(); 152 | } 153 | } 154 | 155 | /** 156 | * 分段读 157 | * 158 | * @param br 159 | * @throws IOException 160 | */ 161 | public static StringBuffer segmentRead(BufferedReader br) throws IOException { 162 | StringBuffer sb = new StringBuffer(); 163 | String line; 164 | while ((line = br.readLine()) != null) { 165 | sb.append(line); 166 | } 167 | return sb; 168 | } 169 | 170 | /** 171 | * 分段写 172 | * 173 | * @param bytes 174 | * @param outputStream 175 | * @throws IOException 176 | */ 177 | public static void segmentWrite(byte[] bytes, OutputStream outputStream) throws IOException { 178 | int length = bytes.length; 179 | int start, end = 0; 180 | for (int i = 0; end != bytes.length; i++) { 181 | start = i == 0 ? 0 : i * SIZE; 182 | end = length > SIZE ? start + SIZE : bytes.length; 183 | length -= SIZE; 184 | outputStream.write(bytes, start, end - start); 185 | outputStream.flush(); 186 | } 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/demo/five/ThreadDemo.java: -------------------------------------------------------------------------------- 1 | package demo.five; 2 | 3 | import org.junit.Test; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * ThreadDemo 9 | *author wenhe 10 | *date 2019/9/5 11 | */ 12 | @Slf4j 13 | public class ThreadDemo { 14 | 15 | class MyThread extends Thread{ 16 | @Override 17 | public void run() { 18 | log.info(Thread.currentThread().getName()); 19 | } 20 | } 21 | @Test 22 | public void extendThreadInit(){ 23 | new MyThread().start(); 24 | } 25 | 26 | @Test 27 | public void init(){ 28 | log.info("{} is run。",Thread.currentThread().getName()); 29 | Thread thread = new Thread(new Runnable() { 30 | @Override 31 | public void run() { 32 | log.info("{} begin run",Thread.currentThread().getName()); 33 | } 34 | }); 35 | // 开一个子线程去执行 36 | thread.start(); 37 | // 不会新起线程,是在当前主线程上继续运行 38 | thread.run(); 39 | } 40 | 41 | @Test 42 | public void join() throws Exception { 43 | Thread main = Thread.currentThread(); 44 | log.info("{} is run。",main.getName()); 45 | Thread thread = new Thread(new Runnable() { 46 | @Override 47 | public void run() { 48 | log.info("{} begin run",Thread.currentThread().getName()); 49 | try { 50 | Thread.sleep(30000L); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | log.info("{} end run",Thread.currentThread().getName()); 55 | } 56 | }); 57 | // 开一个子线程去执行 58 | thread.start(); 59 | thread.join(); 60 | 61 | log.info("{} is end", Thread.currentThread()); 62 | } 63 | 64 | @Test 65 | public void testWait() throws InterruptedException { 66 | String s ="nihao"; 67 | Thread thread = new Thread(new Runnable() { 68 | @Override 69 | public void run() { 70 | log.info("{} begin run",Thread.currentThread().getName()); 71 | try { 72 | Thread.sleep(3000L); 73 | synchronized (s){ 74 | s.notify(); 75 | } 76 | } catch (InterruptedException e) { 77 | e.printStackTrace(); 78 | } 79 | log.info("{} end run",Thread.currentThread().getName()); 80 | } 81 | }); 82 | // 开一个子线程去执行 83 | thread.start(); 84 | synchronized (s){ 85 | s.wait(); 86 | } 87 | log.info("{} is end", Thread.currentThread()); 88 | } 89 | 90 | 91 | @Test 92 | public void testInterrupt() throws InterruptedException { 93 | Thread thread = new Thread(new Runnable() { 94 | @Override 95 | public void run() { 96 | log.info("{} begin run",Thread.currentThread().getName()); 97 | try { 98 | log.info("子线程开始沉睡 30 s"); 99 | Thread.sleep(30000L); 100 | } catch (InterruptedException e) { 101 | log.info("子线程被打断"); 102 | e.printStackTrace(); 103 | } 104 | log.info("{} end run",Thread.currentThread().getName()); 105 | } 106 | }); 107 | // 开一个子线程去执行 108 | thread.start(); 109 | Thread.sleep(10000000L); 110 | log.info("主线程等待 1s 后,发现子线程还没有运行成功,打断子线程"); 111 | thread.interrupt(); 112 | } 113 | 114 | @Test 115 | public void testStackTrace() { 116 | try { 117 | throw new RuntimeException("nihao"); 118 | } catch (Exception e) { 119 | StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 120 | e.printStackTrace(); 121 | } 122 | } 123 | 124 | @Test 125 | public void testYield(){ 126 | boolean stop = false; 127 | while (!stop){ 128 | // dosomething 129 | Thread.yield(); 130 | } 131 | } 132 | 133 | @Test 134 | public void testJoin2() throws Exception { 135 | 136 | Thread thread2 = new Thread(new Runnable() { 137 | @Override 138 | public void run() { 139 | log.info("我是子线程 2,开始沉睡"); 140 | try { 141 | Thread.sleep(2000L); 142 | } catch (InterruptedException e) { 143 | e.printStackTrace(); 144 | } 145 | log.info("我是子线程 2,执行完成"); 146 | } 147 | }); 148 | 149 | Thread thread1 = new Thread(new Runnable() { 150 | @Override 151 | public void run() { 152 | log.info("我是子线程 1,开始运行"); 153 | try { 154 | log.info("我是子线程 1,我在等待子线程 2"); 155 | thread2.join(); 156 | log.info("我是子线程 1,子线程 2 执行完成,我继续执行"); 157 | } catch (InterruptedException e) { 158 | e.printStackTrace(); 159 | } 160 | log.info("我是子线程 1,执行完成"); 161 | } 162 | }); 163 | thread1.start(); 164 | thread2.start(); 165 | Thread.sleep(100000); 166 | } 167 | 168 | // 共享变量 1 169 | private static final Object share1 = new Object(); 170 | // 共享变量 2 171 | private static final Object share2 = new Object(); 172 | @Test 173 | public void testDeadLock() throws InterruptedException { 174 | // 初始化线程 1,线程 1 需要在锁定 share1 共享资源的情况下再锁定 share2 175 | Thread thread1 = new Thread(() -> { 176 | synchronized (share1){ 177 | try { 178 | Thread.sleep(2000); 179 | } catch (InterruptedException e) { 180 | e.printStackTrace(); 181 | } 182 | synchronized (share2){ 183 | log.info("{} is run",Thread.currentThread().getName()); 184 | } 185 | } 186 | }); 187 | 188 | // 初始化线程 2,线程 2 需要在锁定 share2 共享资源的情况下再锁定 share1 189 | Thread thread2 = new Thread(() -> { 190 | synchronized (share2){ 191 | try { 192 | Thread.sleep(2000); 193 | } catch (InterruptedException e) { 194 | e.printStackTrace(); 195 | } 196 | synchronized (share1){ 197 | log.info("{} is run",Thread.currentThread().getName()); 198 | } 199 | } 200 | }); 201 | // 当线程 1、2 启动后,都在等待对方锁定的资源,但都得不到,造成死锁 202 | thread1.start(); 203 | thread2.start(); 204 | Thread.sleep(1000000000); 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /src/main/java/demo/two/HashMapDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.google.common.collect.MapDifference; 6 | import com.google.common.collect.Maps; 7 | import org.junit.Test; 8 | import java.io.Serializable; 9 | import java.lang.reflect.Field; 10 | import java.util.Collection; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.Random; 14 | import java.util.Set; 15 | import java.util.function.ObjDoubleConsumer; 16 | 17 | import lombok.extern.slf4j.Slf4j; 18 | 19 | /** 20 | * ArrayListDemo 21 | *author wenhe 22 | */ 23 | @Slf4j 24 | public class HashMapDemo { 25 | 26 | @Test 27 | public void testRemove(){ 28 | HashMap map = Maps.newHashMap(); 29 | map.put("1","1"); 30 | map.put("2","2"); 31 | 32 | map.forEach((s, s2) -> map.remove("1")); 33 | } 34 | 35 | class DemoDTO implements Serializable,Comparable{ 36 | private static final long serialVersionUID = -5222606202683030702L; 37 | 38 | private Integer i; 39 | 40 | public DemoDTO(Integer i) { 41 | this.i = i; 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return 2; 47 | } 48 | 49 | 50 | @Override 51 | public int compareTo(String o) { 52 | return 1; 53 | } 54 | } 55 | 56 | 57 | @Test 58 | public void testHashTreeNode(){ 59 | Map map = new HashMap(); 60 | for(int i=0;i<32;i++){ 61 | map.put(new DemoDTO(i),i); 62 | } 63 | log.info(JSON.toJSONString(map)); 64 | } 65 | 66 | @Test 67 | public void testArray(){ 68 | String[] array = new String[]{"1", "2", "3"}; 69 | String[] array1 = array; 70 | log.info("array[0] ={}",array[0]); 71 | log.info("array1[0] ={}",array1[0]); 72 | array[0] ="4"; 73 | log.info("array[0] 的值被改变"); 74 | log.info("array[0] ={}",array[0]); 75 | log.info("array1[0] ={}",array1[0]); 76 | } 77 | 78 | @Test 79 | public void compute(){ 80 | HashMap map = Maps.newHashMap(); 81 | map.put(10,10); 82 | log.info("compute 之前值为:{}",map.get(10)); 83 | map.compute(10,(key,value) -> key * value); 84 | log.info("compute 之后值为:{}",map.get(10)); 85 | // 还原测试值 86 | map.put(10,10); 87 | 88 | // 如果为 11 的 key 不存在的话,需要注意 value 为空的情况 89 | // map.compute(11,(key,value) -> key * value); 90 | // 自己判断空指针 91 | map.compute(11,(key,value) -> null == value ? null : key * value); 92 | // computeIfPresent 方法里面判断 93 | map.computeIfPresent(11,(key,value) -> key * value); 94 | log.info("computeIfPresent 之后值为:{}",map.get(11)); 95 | } 96 | 97 | @Test 98 | public void testInitMapByMaps(){ 99 | Map hashMap = Maps.newHashMap(); 100 | Map linkedHashMap = Maps.newLinkedHashMap(); 101 | Map withExpectedSizeHashMap = Maps.newHashMapWithExpectedSize(20); 102 | } 103 | 104 | 105 | @Test 106 | public void testDifference(){ 107 | new HashMap<>(5); 108 | Map leftMap = ImmutableMap.of("1","1","2","2","3","3"); 109 | Map rightMap = ImmutableMap.of("2","2","3","30","4","4"); 110 | MapDifference difference = Maps.difference(leftMap, rightMap); 111 | log.info("左边 map 独有 key:{}",difference.entriesOnlyOnLeft()); 112 | log.info("右边 map 独有 key:{}",difference.entriesOnlyOnRight()); 113 | log.info("左右边 map 都有 key,并且 value 相等:{}",difference.entriesInCommon()); 114 | log.info("左右边 map 都有 key,但 value 不等:{}",difference.entriesDiffering()); 115 | } 116 | 117 | @Test 118 | public void testHash(){ 119 | HashMap oldCountMap = new HashMap<>(); 120 | HashMap newCountMap = new HashMap<>(); 121 | for (int i = 0; i < 1000000; i++) { 122 | // 随机得到 16 位字符串 123 | String s = getRandomString(16); 124 | // 就是简单的 hash 125 | int oldIndex = (getTableLenth(oldCountMap)-1) & s.hashCode(); 126 | // 使用 hashmap 的方法 127 | int newIndex = (newCountMap.size()-1) & (s.hashCode() ^ (s.hashCode() >>> 16)); 128 | 129 | double oldValue = oldCountMap.getOrDefault(oldIndex,0d); 130 | oldCountMap.put(oldIndex, ++oldValue); 131 | 132 | double newValue = newCountMap.getOrDefault(newIndex,0d); 133 | newCountMap.put(newIndex, ++newValue); 134 | } 135 | HashMapDemo demo = new HashMapDemo(); 136 | Double[] oldArry = new Double[oldCountMap.values().size()]; 137 | oldCountMap.values().toArray(oldArry); 138 | 139 | Double[] newArry = new Double[newCountMap.values().size()]; 140 | newCountMap.values().toArray(newArry); 141 | 142 | System.out.println(demo.variance(oldArry)); 143 | System.out.println(demo.variance(newArry)); 144 | } 145 | 146 | private int getTableLenth(HashMap map){ 147 | try{ 148 | Class clazz = Class.forName("java.util.HashMap"); 149 | Field field = clazz.getDeclaredField("table"); 150 | field.setAccessible(true); 151 | // 拿到 string 里面的数组 152 | Object table = field.get(map); 153 | return 0; 154 | }catch(Exception e){ 155 | } 156 | return 0; 157 | } 158 | 159 | public double variance(Double[] x) { 160 | int m = x.length; 161 | double sum = 0; 162 | for (int i = 0; i < m; i++) {//求和 163 | sum += x[i]; 164 | } 165 | double dAve = sum / m;//求平均值 166 | double dVar = 0; 167 | for (int i = 0; i < m; i++) {//求方差 168 | dVar += (x[i] - dAve) * (x[i] - dAve); 169 | } 170 | return dVar / m; 171 | } 172 | 173 | public static String getRandomString(int length){ 174 | String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 175 | Random random=new Random(); 176 | StringBuffer sb=new StringBuffer(); 177 | for(int i=0;i map = new HashMap<>(1); 195 | for(int i=0;i<67;i++){ 196 | if(i ==0){ 197 | map.put(i+"",i+""); 198 | }else if(i ==15){ 199 | map.put(i+"",i+""); 200 | }else { 201 | map.put(i+"",i+""); 202 | } 203 | } 204 | } 205 | 206 | @Test 207 | public void test(){ 208 | HashMap map = new HashMap<>(); 209 | map.put("key","value"); 210 | Set> set = map.entrySet(); 211 | Collection values = map.values(); 212 | } 213 | 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/demo/two/ArrayListDemo.java: -------------------------------------------------------------------------------- 1 | package demo.two; 2 | import java.util.HashSet; 3 | import java.util.concurrent.locks.ReentrantLock; 4 | import java.lang.reflect.Field; 5 | 6 | import com.alibaba.fastjson.JSON; 7 | import com.google.common.collect.Lists; 8 | 9 | import org.junit.Test; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.concurrent.ExecutionException; 15 | import java.util.concurrent.Executors; 16 | import java.util.concurrent.FutureTask; 17 | 18 | import lombok.extern.slf4j.Slf4j; 19 | 20 | /** 21 | * ArrayListDemo 22 | *author wenhe 23 | */ 24 | @Slf4j 25 | public class ArrayListDemo { 26 | 27 | @Test 28 | public void initByCollection(){ 29 | // Arrays.asList 返回的是具体的类型 30 | List list = Arrays.asList("hello,world"); 31 | Object[] objArray = list.toArray(); 32 | log.info(objArray.getClass().getSimpleName()); 33 | // objArray 元素的类型是 String,储存 Object 就会报错,因为 jvm 不清楚你存储的 34 | // Object 真实类型是不是 String 35 | objArray[0] = new Object(); 36 | } 37 | 38 | @Test 39 | public void testRemove(){ 40 | List list = new ArrayList() {{ 41 | add("2"); 42 | add("3"); 43 | add("3"); 44 | add("3"); 45 | add("4"); 46 | }}; 47 | for (int i = 0; i < list.size(); i++) { 48 | if (list.get(i).equals("3")) { 49 | list.remove(i); 50 | } 51 | } 52 | } 53 | 54 | @Test 55 | public void testBatchInsert(){ 56 | // 准备数据 57 | ArrayList list = new ArrayList<>(); 58 | for(int i=0;i<3000000;i++){ 59 | list.add(i); 60 | } 61 | 62 | // for 循环 使用add方法新增 63 | ArrayList list2 = new ArrayList<>(); 64 | long start1 = System.currentTimeMillis(); 65 | for(int i=0;i list3 = new ArrayList<>(); 72 | long start2 = System.currentTimeMillis(); 73 | list3.addAll(list); 74 | log.info("批量新增 300 w 个,耗时{}",System.currentTimeMillis()-start2); 75 | } 76 | 77 | @Test 78 | public void testArrayToList(){ 79 | Integer[] array = new Integer[]{1,2,3,4,5,6}; 80 | List list = Arrays.asList(array); 81 | 82 | // 修改数组的值,会直接影响 list 83 | log.info("数组被修改之前,集合第一个元素为:{}",list.get(0)); 84 | array[0] = 10; 85 | log.info("数组被修改之前,集合第一个元素为:{}",list.get(0)); 86 | 87 | // 使用 add、remove 等操作 list 的方法时, 88 | // 会报 UnsupportedOperationException 异常 89 | list.add(7); 90 | } 91 | 92 | @Test 93 | public void testListToArray(){ 94 | List list = new ArrayList(){{ 95 | add(1); 96 | add(2); 97 | add(3); 98 | add(4); 99 | }}; 100 | 101 | // 这样子无法转化,无参 toArray 返回的是 Object[], 102 | // 无法向下强转,编译无法通过,很麻烦 103 | // List list2 = list.toArray(); 104 | 105 | // 演示有参 toArray 方法,数组大小不够时,数组为 null 情况 106 | Integer[] array0 = new Integer[2]; 107 | list.toArray(array0); 108 | log.info("toArray 数组大小不够,array0 数组[0] 值是{},数组[1] 值是{},",array0[0],array0[1]); 109 | 110 | Integer[] array1 = new Integer[list.size()]; 111 | list.toArray(array1); 112 | log.info("toArray 数组大小正好,array1 数组[3] 值是{}",array1[3]); 113 | 114 | Integer[] array2 = new Integer[list.size()+2]; 115 | list.toArray(array2); 116 | log.info("toArray 数组大小多了,array2 数组[3] 值是{},数组[4] 值是{}",array2[3],array2[4]); 117 | } 118 | 119 | @Test 120 | public void testForEach(){ 121 | List list = new ArrayList(){{ 122 | add(1); 123 | add(3); 124 | add(2); 125 | add(4); 126 | }}; 127 | 128 | list.forEach( value->log.info("当前值为:{}",value)); 129 | } 130 | 131 | @Test 132 | public void testArrayParallel(){ 133 | int size = 1 << 13; 134 | log.info(""+size); 135 | Integer[] array = new Integer[size+2]; 136 | for(int i=0;i list = new ArrayList(){{ 145 | add("10"); 146 | add("20"); 147 | add("30"); 148 | add("40"); 149 | }}; 150 | log.info("反转之前:"+JSON.toJSONString(list)); 151 | list = Lists.reverse(list); 152 | log.info("反转之后:"+JSON.toJSONString(list)); 153 | } 154 | 155 | @Test 156 | public void testPartition(){ 157 | List list = new ArrayList(){{ 158 | add("10"); 159 | add("20"); 160 | add("30"); 161 | add("40"); 162 | }}; 163 | log.info("分组之前:"+JSON.toJSONString(list)); 164 | List> list2 = Lists.partition(list,3); 165 | log.info("分组之后:"+JSON.toJSONString(list2)); 166 | 167 | Long a =100L; 168 | a =10L; 169 | } 170 | 171 | @Test 172 | public void testMath(){ 173 | int n =30; 174 | int i =n >>>3; 175 | log.info(i+""); 176 | int ii = n <<1; 177 | log.info(ii+""); 178 | } 179 | 180 | public static void main(String[] args) throws ExecutionException, InterruptedException { 181 | FutureTask futureTask = new FutureTask(() -> "nihao"); 182 | Executors.newFixedThreadPool(10).submit(futureTask); 183 | futureTask.get(); 184 | System.out.println("cdcd"); 185 | } 186 | 187 | @Test 188 | public void string() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 189 | String str = "hello world"; 190 | Class clazz = Class.forName("java.lang.String"); 191 | Field field = clazz.getDeclaredField("value"); 192 | field.setAccessible(true); 193 | // 拿到 string 里面的数组 194 | char[] value = (char[]) field.get(str); 195 | log.info("修改之前{}",str); 196 | field.set(str,"hello java".toCharArray()); 197 | log.info("修改之后{}",str); 198 | 199 | 200 | } 201 | 202 | @Test 203 | public void testFor(){ 204 | List list = new ArrayList (5000); 205 | for (int i = 0; i < 5000; i++) { 206 | list.add(i); 207 | } 208 | } 209 | 210 | @Test 211 | public void testParse() throws InterruptedException { 212 | log.info("----"); 213 | Thread.sleep(1000L); 214 | String s ="100"; 215 | int valueOf = 0; 216 | int parseLong = 0; 217 | for(int y=0;y<100;y++){ 218 | long beginTime = System.currentTimeMillis(); 219 | for (int i = 0; i < 1000; i++) { 220 | Long.valueOf(s); 221 | } 222 | Long s11 = System.currentTimeMillis() - beginTime; 223 | long beginTime1 = System.currentTimeMillis(); 224 | for (int i = 0; i < 1000; i++) { 225 | Long.parseLong(s); 226 | } 227 | Long s22 = System.currentTimeMillis() - beginTime1; 228 | 229 | if(s11>s22){ 230 | parseLong++; 231 | }else { 232 | valueOf++; 233 | } 234 | } 235 | System.out.println("valueOf 累计"+valueOf); 236 | System.out.println("parseLong 累计"+parseLong); 237 | 238 | } 239 | 240 | 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/demo/sixth/MysqlConnection.java: -------------------------------------------------------------------------------- 1 | package demo.sixth; 2 | 3 | import java.sql.Array; 4 | import java.sql.Blob; 5 | import java.sql.CallableStatement; 6 | import java.sql.Clob; 7 | import java.sql.Connection; 8 | import java.sql.DatabaseMetaData; 9 | import java.sql.NClob; 10 | import java.sql.PreparedStatement; 11 | import java.sql.SQLClientInfoException; 12 | import java.sql.SQLException; 13 | import java.sql.SQLWarning; 14 | import java.sql.SQLXML; 15 | import java.sql.Savepoint; 16 | import java.sql.Statement; 17 | import java.sql.Struct; 18 | import java.util.Map; 19 | import java.util.Properties; 20 | import java.util.concurrent.Executor; 21 | 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | /** 25 | * 得到 mysql 链接 26 | *author wenhe 27 | *date 2019/9/28 28 | */ 29 | @Slf4j 30 | public class MysqlConnection { 31 | 32 | private final ShareLock lock; 33 | 34 | // maxConnectionSize 表示最大链接数 35 | public MysqlConnection(int maxConnectionSize) { 36 | lock = new ShareLock(maxConnectionSize); 37 | } 38 | 39 | // 对外获取 mysql 链接的接口 40 | // 这里不用try finally 的结构,获得锁实现底层不会有异常 41 | // 即使出现未知异常,也无需释放锁 42 | public Connection getLimitConnection() { 43 | if (lock.lock()) { 44 | return getConnection(); 45 | } 46 | return null; 47 | } 48 | 49 | // 对外释放 mysql 链接的接口 50 | public boolean releaseLimitConnection() { 51 | return lock.unLock(); 52 | } 53 | 54 | public static void main(String[] args) { 55 | log.info("模仿开始获得 mysql 链接"); 56 | MysqlConnection mysqlConnection = new MysqlConnection(10); 57 | log.info("初始化 Mysql 链接最大只能获取 10 个"); 58 | for(int i =0 ;i<12;i++){ 59 | if(null != mysqlConnection.getLimitConnection()){ 60 | log.info("获得第{}个数据库链接成功",i+1); 61 | }else { 62 | log.info("获得第{}个数据库链接失败:数据库连接池已满",i+1); 63 | } 64 | } 65 | log.info("模仿开始释放 mysql 链接"); 66 | for(int i =0 ;i<12;i++){ 67 | if(mysqlConnection.releaseLimitConnection()){ 68 | log.info("释放第{}个数据库链接成功",i+1); 69 | }else { 70 | log.info("释放第{}个数据库链接失败",i+1); 71 | } 72 | } 73 | log.info("模仿结束"); 74 | } 75 | 76 | // 得到一个 mysql 链接,底层实现省略 77 | private Connection getConnection(){ 78 | return new Connection(){ 79 | 80 | @Override 81 | public T unwrap(Class iface) throws SQLException { 82 | return null; 83 | } 84 | 85 | @Override 86 | public boolean isWrapperFor(Class iface) throws SQLException { 87 | return false; 88 | } 89 | 90 | @Override 91 | public Statement createStatement() throws SQLException { 92 | return null; 93 | } 94 | 95 | @Override 96 | public PreparedStatement prepareStatement(String sql) throws SQLException { 97 | return null; 98 | } 99 | 100 | @Override 101 | public CallableStatement prepareCall(String sql) throws SQLException { 102 | return null; 103 | } 104 | 105 | @Override 106 | public String nativeSQL(String sql) throws SQLException { 107 | return null; 108 | } 109 | 110 | @Override 111 | public void setAutoCommit(boolean autoCommit) throws SQLException { 112 | 113 | } 114 | 115 | @Override 116 | public boolean getAutoCommit() throws SQLException { 117 | return false; 118 | } 119 | 120 | @Override 121 | public void commit() throws SQLException { 122 | 123 | } 124 | 125 | @Override 126 | public void rollback() throws SQLException { 127 | 128 | } 129 | 130 | @Override 131 | public void close() throws SQLException { 132 | 133 | } 134 | 135 | @Override 136 | public boolean isClosed() throws SQLException { 137 | return false; 138 | } 139 | 140 | @Override 141 | public DatabaseMetaData getMetaData() throws SQLException { 142 | return null; 143 | } 144 | 145 | @Override 146 | public void setReadOnly(boolean readOnly) throws SQLException { 147 | 148 | } 149 | 150 | @Override 151 | public boolean isReadOnly() throws SQLException { 152 | return false; 153 | } 154 | 155 | @Override 156 | public void setCatalog(String catalog) throws SQLException { 157 | 158 | } 159 | 160 | @Override 161 | public String getCatalog() throws SQLException { 162 | return null; 163 | } 164 | 165 | @Override 166 | public void setTransactionIsolation(int level) throws SQLException { 167 | 168 | } 169 | 170 | @Override 171 | public int getTransactionIsolation() throws SQLException { 172 | return 0; 173 | } 174 | 175 | @Override 176 | public SQLWarning getWarnings() throws SQLException { 177 | return null; 178 | } 179 | 180 | @Override 181 | public void clearWarnings() throws SQLException { 182 | 183 | } 184 | 185 | @Override 186 | public Statement createStatement(int resultSetType, int resultSetConcurrency) 187 | throws SQLException { 188 | return null; 189 | } 190 | 191 | @Override 192 | public PreparedStatement prepareStatement(String sql, int resultSetType, 193 | int resultSetConcurrency) throws SQLException { 194 | return null; 195 | } 196 | 197 | @Override 198 | public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) 199 | throws SQLException { 200 | return null; 201 | } 202 | 203 | @Override 204 | public Map> getTypeMap() throws SQLException { 205 | return null; 206 | } 207 | 208 | @Override 209 | public void setTypeMap(Map> map) throws SQLException { 210 | 211 | } 212 | 213 | @Override 214 | public void setHoldability(int holdability) throws SQLException { 215 | 216 | } 217 | 218 | @Override 219 | public int getHoldability() throws SQLException { 220 | return 0; 221 | } 222 | 223 | @Override 224 | public Savepoint setSavepoint() throws SQLException { 225 | return null; 226 | } 227 | 228 | @Override 229 | public Savepoint setSavepoint(String name) throws SQLException { 230 | return null; 231 | } 232 | 233 | @Override 234 | public void rollback(Savepoint savepoint) throws SQLException { 235 | 236 | } 237 | 238 | @Override 239 | public void releaseSavepoint(Savepoint savepoint) throws SQLException { 240 | 241 | } 242 | 243 | @Override 244 | public Statement createStatement(int resultSetType, int resultSetConcurrency, 245 | int resultSetHoldability) throws SQLException { 246 | return null; 247 | } 248 | 249 | @Override 250 | public PreparedStatement prepareStatement(String sql, int resultSetType, 251 | int resultSetConcurrency, int resultSetHoldability) 252 | throws SQLException { 253 | return null; 254 | } 255 | 256 | @Override 257 | public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, 258 | int resultSetHoldability) throws SQLException { 259 | return null; 260 | } 261 | 262 | @Override 263 | public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) 264 | throws SQLException { 265 | return null; 266 | } 267 | 268 | @Override 269 | public PreparedStatement prepareStatement(String sql, int[] columnIndexes) 270 | throws SQLException { 271 | return null; 272 | } 273 | 274 | @Override 275 | public PreparedStatement prepareStatement(String sql, String[] columnNames) 276 | throws SQLException { 277 | return null; 278 | } 279 | 280 | @Override 281 | public Clob createClob() throws SQLException { 282 | return null; 283 | } 284 | 285 | @Override 286 | public Blob createBlob() throws SQLException { 287 | return null; 288 | } 289 | 290 | @Override 291 | public NClob createNClob() throws SQLException { 292 | return null; 293 | } 294 | 295 | @Override 296 | public SQLXML createSQLXML() throws SQLException { 297 | return null; 298 | } 299 | 300 | @Override 301 | public boolean isValid(int timeout) throws SQLException { 302 | return false; 303 | } 304 | 305 | @Override 306 | public void setClientInfo(String name, String value) throws SQLClientInfoException { 307 | 308 | } 309 | 310 | @Override 311 | public void setClientInfo(Properties properties) throws SQLClientInfoException { 312 | 313 | } 314 | 315 | @Override 316 | public String getClientInfo(String name) throws SQLException { 317 | return null; 318 | } 319 | 320 | @Override 321 | public Properties getClientInfo() throws SQLException { 322 | return null; 323 | } 324 | 325 | @Override 326 | public Array createArrayOf(String typeName, Object[] elements) throws SQLException { 327 | return null; 328 | } 329 | 330 | @Override 331 | public Struct createStruct(String typeName, Object[] attributes) throws SQLException { 332 | return null; 333 | } 334 | 335 | @Override 336 | public void setSchema(String schema) throws SQLException { 337 | 338 | } 339 | 340 | @Override 341 | public String getSchema() throws SQLException { 342 | return null; 343 | } 344 | 345 | @Override 346 | public void abort(Executor executor) throws SQLException { 347 | 348 | } 349 | 350 | @Override 351 | public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { 352 | 353 | } 354 | 355 | @Override 356 | public int getNetworkTimeout() throws SQLException { 357 | return 0; 358 | } 359 | }; 360 | } 361 | 362 | } 363 | -------------------------------------------------------------------------------- /src/main/java/demo/eight/LambdaExpressionDemo.java: -------------------------------------------------------------------------------- 1 | package demo.eight; 2 | 3 | 4 | import com.alibaba.fastjson.JSON; 5 | import com.google.common.collect.ImmutableList; 6 | import com.google.common.collect.ImmutableMap; 7 | import com.google.common.collect.Lists; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.junit.Test; 11 | 12 | import java.io.Serializable; 13 | import java.util.ArrayList; 14 | import java.util.Comparator; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.Optional; 18 | import java.util.Set; 19 | import java.util.stream.Collectors; 20 | import java.util.stream.Stream; 21 | 22 | import lombok.Data; 23 | import lombok.extern.slf4j.Slf4j; 24 | 25 | /** 26 | * lambda 表达式 author wenhe date 2019/10/12 27 | */ 28 | @Slf4j 29 | public class LambdaExpressionDemo { 30 | 31 | private static final List list = ImmutableList.of("hello", "world"); 32 | 33 | @Data 34 | // 学生数据结构 35 | class StudentDTO implements Serializable { 36 | 37 | private static final long serialVersionUID = -7716352032236707189L; 38 | 39 | public StudentDTO() { 40 | } 41 | 42 | public StudentDTO(Long id, String code, String name, String sex, Double scope, 43 | List learningCources) { 44 | this.id = id; 45 | this.code = code; 46 | this.name = name; 47 | this.sex = sex; 48 | this.scope = scope; 49 | this.learningCources = learningCources; 50 | } 51 | 52 | /** 53 | * id 54 | */ 55 | private Long id; 56 | /** 57 | * 学号 唯一标识 58 | */ 59 | private String code; 60 | /** 61 | * 学生名字 62 | */ 63 | private String name; 64 | 65 | /** 66 | * 性别 67 | */ 68 | private String sex; 69 | 70 | /** 71 | * 分数 72 | */ 73 | private Double scope; 74 | 75 | /** 76 | * 要学习的课程 77 | */ 78 | private List learningCources; 79 | } 80 | 81 | @Data 82 | // 课程数据结构 83 | class Course implements Serializable { 84 | 85 | private static final long serialVersionUID = 2896201730223729591L; 86 | 87 | /** 88 | * 课程 ID 89 | */ 90 | private Long id; 91 | 92 | /** 93 | * 课程 name 94 | */ 95 | private String name; 96 | 97 | public Course(Long id, String name) { 98 | this.id = id; 99 | this.name = name; 100 | } 101 | } 102 | // 初始化数据 103 | private final List students = new ArrayList(){ 104 | { 105 | // 添加学生数据 106 | add(new StudentDTO(1L,"W199","小美","WM",100D,new ArrayList(){ 107 | { 108 | // 添加学生学习的课程 109 | add(new Course(300L,"语文")); 110 | add(new Course(301L,"数学")); 111 | add(new Course(302L,"英语")); 112 | } 113 | })); 114 | add(new StudentDTO(2L,"W25","小美","WM",100D,Lists.newArrayList())); 115 | add(new StudentDTO(3L,"W3","小名","M",90D,new ArrayList(){ 116 | { 117 | add(new Course(300L,"语文")); 118 | add(new Course(304L,"体育")); 119 | } 120 | })); 121 | add(new StudentDTO(4L,"W1","小蓝","M",10D,new ArrayList(){ 122 | { 123 | add(new Course(301L,"数学")); 124 | add(new Course(305L,"美术")); 125 | } 126 | })); 127 | } 128 | }; 129 | 130 | 131 | @Test 132 | public void testFilter() { 133 | List newList = list.stream() 134 | // 过滤掉我们希望留下来的值 135 | // StringUtils.equals(str,"hello") 表示我们希望字符串是 hello 能留下来 136 | // 其他的过滤掉 137 | .filter(str -> StringUtils.equals(str, "hello")) 138 | // Collectors.toList() 帮助我们构造最后的返回结果 139 | .collect(Collectors.toList()); 140 | log.info("TestFilter result is {}", JSON.toJSONString(newList)); 141 | } 142 | 143 | // map 方法可以让我们进行一些流的转化,比如原来流中的元素是 A,通过 map 操作,可以使返回的流中的元素是 B 144 | @Test 145 | public void testMap() { 146 | // 得到所有学生的学号 147 | // 这里 students.stream() 中的元素是 StudentDTO,通过 map 转化成 String 的流 148 | List codes = students.stream() 149 | //StudentDTO::getCode 是 s->s.getCode() 的简写 150 | .map(StudentDTO::getCode) 151 | .collect(Collectors.toList()); 152 | log.info("TestMap 所有学生的学号为 {}", JSON.toJSONString(codes)); 153 | } 154 | 155 | // mapToInt 固定返回流的类型是 int,还有 mapToLong,mapToDouble 156 | @Test 157 | public void testMapToInt() { 158 | List ids = students.stream() 159 | .mapToInt(s->Integer.valueOf(s.getId()+"")) 160 | // 一定要有 mapToObj,因为 mapToInt 返回的是 IntStream,因为已经确定是 int 类型了 161 | // 所有没有泛型的,而 Collectors.toList() 强制要求有泛型的流,所以需要使用 mapToObj 162 | // 方法返回有泛型的流 163 | .mapToObj(s->s) 164 | .collect(Collectors.toList()); 165 | log.info("TestMapToInt result is {}", JSON.toJSONString(ids)); 166 | 167 | // 计算学生总分 168 | Double sumScope = students.stream() 169 | .mapToDouble(s->s.getScope()) 170 | // IntStream 有许多 sum(求和)、min(求最小值)、max(求最大值)、average(求平均值)等方法 171 | .sum(); 172 | log.info("TestMapToInt 学生总分为: is {}", sumScope); 173 | } 174 | 175 | // flatMap 方法和 map 方法不同,FlatMap 可以接受入参的类型为 Stream,比如这里的 176 | // s.getLearningCources().stream() 就是 Stream,可以用下面的 demo 比较一下差异 177 | @Test 178 | public void testFlatMap(){ 179 | // 计算学生所有的学习课程,flatMap 返回 List<课程> 格式 180 | List courses = students.stream().flatMap(s->s.getLearningCources().stream()) 181 | .collect(Collectors.toList()); 182 | log.info("TestMapToInt flatMap 计算学生的所有学习课程如下 {}", JSON.toJSONString(courses)); 183 | 184 | // 计算学生所有的学习课程,map 返回两层课程嵌套格式 185 | List> courses2 = students.stream().map(s->s.getLearningCources()) 186 | .collect(Collectors.toList()); 187 | log.info("TestMapToInt map 计算学生的所有学习课程如下 {}", JSON.toJSONString(courses2)); 188 | 189 | List> courses3 = students.stream().map(s->s.getLearningCources().stream()) 190 | .collect(Collectors.toList()); 191 | log.info("TestMapToInt map 计算学生的所有学习课程如下 {}", JSON.toJSONString(courses3)); 192 | } 193 | 194 | // 去重 195 | @Test 196 | public void testDistinct(){ 197 | // 得到学生所有的名字,要求是去重过的 198 | List beforeNames = students.stream().map(StudentDTO::getName).collect(Collectors.toList()); 199 | log.info("TestDistinct 没有去重前的学生名单 {}",JSON.toJSONString(beforeNames)); 200 | 201 | List distinctNames = beforeNames.stream().distinct().collect(Collectors.toList()); 202 | log.info("TestDistinct 去重后的学生名单 {}",JSON.toJSONString(distinctNames)); 203 | 204 | // 连起来写 205 | List names = students.stream() 206 | .map(StudentDTO::getName) 207 | .distinct() 208 | .collect(Collectors.toList()); 209 | log.info("TestDistinct 去重后的学生名单 {}",JSON.toJSONString(names)); 210 | } 211 | 212 | // 排序 213 | @Test 214 | public void testSorted(){ 215 | // 学生按照学号排序 216 | List beforeCodes = students.stream().map(StudentDTO::getCode).collect(Collectors.toList()); 217 | log.info("TestSorted 按照学号排序之前 {}",JSON.toJSONString(beforeCodes)); 218 | 219 | List sortedCodes = beforeCodes.stream().sorted().collect(Collectors.toList()); 220 | log.info("TestSorted 按照学号排序之后 is {}",JSON.toJSONString(sortedCodes)); 221 | 222 | // 直接连起来写 223 | List codes = students.stream() 224 | .map(StudentDTO::getCode) 225 | // 等同于 .sorted(Comparator.naturalOrder()) 自然排序 226 | .sorted() 227 | .collect(Collectors.toList()); 228 | log.info("TestSorted 按照自然排序 is {}",JSON.toJSONString(codes)); 229 | 230 | // 自定义排序器 231 | List codes2 = students.stream() 232 | .map(StudentDTO::getCode) 233 | // 反自然排序 234 | .sorted(Comparator.reverseOrder()) 235 | .collect(Collectors.toList()); 236 | log.info("TestSorted 反自然排序 is {}",JSON.toJSONString(codes2)); 237 | } 238 | 239 | // 干任何没有返回值的事情 240 | @Test 241 | public void testPeek(){ 242 | students.stream().map(StudentDTO::getCode) 243 | .peek(s -> log.info("当前循环的学号是{}",s)) 244 | .collect(Collectors.toList()); 245 | } 246 | 247 | // 限制 248 | @Test 249 | public void testLimit(){ 250 | List beforeCodes = students.stream().map(StudentDTO::getCode).collect(Collectors.toList()); 251 | log.info("TestLimit 限制之前学生的学号为 {}",JSON.toJSONString(beforeCodes)); 252 | 253 | List limitCodes = beforeCodes.stream() 254 | .limit(2L) 255 | .collect(Collectors.toList()); 256 | log.info("TestLimit 限制最大限制 2 个学生的学号 {}",JSON.toJSONString(limitCodes)); 257 | 258 | // 直接连起来写 259 | List codes = students.stream() 260 | .map(StudentDTO::getCode) 261 | .limit(2L) 262 | .collect(Collectors.toList()); 263 | log.info("TestLimit 限制最大限制 2 个学生的学号 {}",JSON.toJSONString(codes)); 264 | } 265 | 266 | // 计算一下学生的总分数 267 | @Test 268 | public void testReduce(){ 269 | // 计算一下学生的总分数 270 | Double sum = students.stream() 271 | .map(StudentDTO::getScope) 272 | // scope1 和 scope2 表示循环中的前后两个数 273 | .reduce((scope1,scope2) -> scope1+scope2) 274 | .orElse(0D); 275 | log.info("总成绩为 {}",sum); 276 | 277 | Double sum1 = students.stream() 278 | .map(StudentDTO::getScope) 279 | // 第一个参数表示成绩的基数,会从 100 开始加 280 | .reduce(100D,(scope1,scope2) -> scope1+scope2); 281 | log.info("总成绩为 {}",sum1); 282 | } 283 | 284 | 285 | // 找到第一个叫小美同学的 ID 286 | @Test 287 | public void testFindFirst(){ 288 | Long id = students.stream() 289 | .filter(s->StringUtils.equals(s.getName(),"小美")) 290 | .findFirst() 291 | .get().getId(); 292 | 293 | log.info("testFindFirst 小美同学的 ID {}",id); 294 | 295 | // 防止空指针 296 | Long id2 = students.stream() 297 | .filter(s->StringUtils.equals(s.getName(),"小天")) 298 | .findFirst() 299 | // orElse 表示如果 findFirst 返回 null 的话,就返回 orElse 里的内容 300 | .orElse(new StudentDTO()).getId(); 301 | log.info("testFindFirst 小天同学的 ID {}",id2); 302 | 303 | Optional student= students.stream() 304 | .filter(s->StringUtils.equals(s.getName(),"小天")) 305 | .findFirst(); 306 | // isPresent 为 true 的话,表示 value != null 307 | if(student.isPresent()){ 308 | log.info("testFindFirst 小天同学的 ID {}",student.get().getId()); 309 | return; 310 | } 311 | log.info("testFindFirst 找不到名为小天的同学"); 312 | } 313 | 314 | @Test 315 | public void testListToMap(){ 316 | // 学生根据名字进行分类 317 | Map> map1 = students.stream() 318 | .collect(Collectors.groupingBy(StudentDTO::getName)); 319 | log.info("testListToMap groupingBy 学生根据名字进行分类 result is Map> {}", 320 | JSON.toJSONString(map1)); 321 | 322 | // 统计有没有姓名重名的 323 | Map> map2 = students.stream() 324 | .collect(Collectors.groupingBy(StudentDTO::getName, 325 | Collectors.mapping(StudentDTO::getCode,Collectors.toSet()))); 326 | log.info("testListToMap groupingBy 统计姓名重名结果 is {}", 327 | JSON.toJSONString(map2)); 328 | 329 | // 学生转化成学号为 key 的 map 330 | Map map3 = students.stream() 331 | .collect(Collectors.toMap(s->s.getCode(),s->s,(s1,s2)->s1)); 332 | log.info("testListToMap groupingBy 学生转化成学号为 key 的 map result is{}", 333 | JSON.toJSONString(map3)); 334 | 335 | } 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | } 349 | --------------------------------------------------------------------------------