java学习2.3.2

Java并发编程:volatile关键字解析 https://www.cnblogs.com/dolphin0520/p/3920373.html

什么是CAS机制? https://blog.csdn.net/qq_32998153/article/details/79529704

  --ConcurrentHashMap1.7使用lock锁实现,1.8使用cas+synchronized ,更多应用见atomic包

分布式锁  https://blog.csdn.net/q975583865/article/details/78375160

nohup java -Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m -Dfile.encoding=UTF8 -Djava.io.tmpdir=tmp -jar stec-szmis-service.jar --management.port=5220 --management.security.enabled=false --management.address=127.0.0.1 --tid F3BC9F237DBD9DBF4D033DB5B9A09EA6>/dev/null 2>&1 &

kill -9 `ps -ef|grep F3BC9F237DBD9DBF4D033DB5B9A09EA6|grep -v grep|awk '{print $2}'`

 

list 多条件排序

List newList = list.sort(Comparator.comparing(Task::getTaskLevel).thenComparing(Task::getTaskNo))


1.多线程

1.1终止多线程

1.不能用stop,要用 thread.interrupt();

2.使用状态标识+volatile

java学习2.3.2_第1张图片

 

1.2wait notify 注意点

1.都必须写在同步代码块中,wait会释放锁

2.wait必须在notify之后执行,否则可能死锁

park unpark 注意点

与wait 不同,与unpark没有顺序要求,但是park不会释放锁!

1.3注意判断条件不要使用if,而是while

必须在同步代码块中使用while来判断线程是否进入等待状态,if可能有伪唤醒(JDK原因)

1.4ReentrantReadWriteLock读写锁

hashtable:synchronized,导致读锁之间的互斥,只有一个线程能读

concurrentmap:ReentrantReadWriteLock,读与读之间能并发

1.5 拆分任务

1.5.1fork join(不适合操作数据库,用得少)

分解任务fork出新任务,聚集join任务结果

ForkJoinTask子类

RecursiveTask (可返回结果)或 RecursiveAction

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.concurrent.*;

/**
 * 并行调用http接口
 */
@Service
public class UserServiceForkJoin {
    // 本质是一个线程池,默认的线程数量:CPU的核数
    ForkJoinPool forkJoinPool = new ForkJoinPool(10, ForkJoinPool.defaultForkJoinWorkerThreadFactory,
            null, true);
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 查询多个系统的数据,合并返回
     */
    public Object getUserInfo(String userId) throws ExecutionException, InterruptedException {
        // 其他例子, 查数据库的多个表数据,分多次查询
        // fork/join
        // forkJoinPool.submit()
        ArrayList urls = new ArrayList<>();
        urls.add("http://www.tony.com/userinfo-api/get?userId=" + userId);
        urls.add("http://www.tony.com/integral-api/get?userId=" + userId);

        HttpJsonRequest httpJsonRequest = new HttpJsonRequest(restTemplate, urls, 0, urls.size() - 1);
        ForkJoinTask forkJoinTask = forkJoinPool.submit(httpJsonRequest);

        JSONObject result = forkJoinTask.get();
        return result;
    }
}

// 任务
class HttpJsonRequest extends RecursiveTask {

    RestTemplate restTemplate;
    ArrayList urls;
    int start;
    int end;

    HttpJsonRequest(RestTemplate restTemplate, ArrayList urls, int start, int end) {
        this.restTemplate = restTemplate;
        this.urls = urls;
        this.start = start;
        this.end = end;
    }

    // 就是实际去执行的一个方法入口(任务拆分)
    @Override
    protected JSONObject compute() {
        int count = end - start; // 代表当前这个task需要处理多少数据
        // 自行根据业务场景去判断是否是大任务,是否需要拆分
        if (count == 0) {
            String url = urls.get(start);
            // TODO 如果只有一个接口调用,立刻调用
            long userinfoTime = System.currentTimeMillis();
            String response = restTemplate.getForObject(url, String.class);
            JSONObject value = JSONObject.parseObject(response);
            System.out.println(Thread.currentThread() + " 接口调用完毕" + (System.currentTimeMillis() - userinfoTime) + " #" + url);
            return value;
        } else { // 如果是多个接口调用,拆分成子任务  7,8,   9,10
            System.out.println(Thread.currentThread() + "任务拆分一次");
            int x = (start + end) / 2;
            HttpJsonRequest httpJsonRequest = new HttpJsonRequest(restTemplate, urls, start, x);// 负责处理哪一部分?
            httpJsonRequest.fork();

            HttpJsonRequest httpJsonRequest1 = new HttpJsonRequest(restTemplate, urls, x + 1, end);// 负责处理哪一部分?
            httpJsonRequest1.fork();

            // join获取处理结果
            JSONObject result = new JSONObject();
            result.putAll(httpJsonRequest.join());
            result.putAll(httpJsonRequest1.join());
            return result;
        }
    }
}



@Autowired
    UserServiceForkJoin userServiceForkJoin;

@controller
public void testUserSerivce() throws Exception {
        // 调用
        long currentTimeMillis = System.currentTimeMillis();
        // http 实际就是 线程 调用service
        Object userInfo = userServiceForkJoin.getUserInfo("tony");

        System.out.println("getUserInfo总执行时间为" + (System.currentTimeMillis() - currentTimeMillis));
        System.out.println(userInfo.toString());
    }

1.5.2   CountDownLatch

ExecutorService executorService = Executors.newCachedThreadPool();

/**
     * 查询多个系统的数据,合并返回
     */
    public Object getUserInfo(String userId) throws InterruptedException {
        CountDownLatch count = new CountDownLatch(2);
        ArrayList values = new ArrayList<>();
        // 你可以封装成一个 提交URL 就能自动多线程调用的 工具
            executorService.submit(() -> {
                // 1. 先从调用获取用户基础信息的http接口
                long userinfoTime = System.currentTimeMillis();
                String value = restTemplate.getForObject("http://www.tony.com/userinfo-api/get?userId=" + userId, String.class);
                JSONObject userInfo = JSONObject.parseObject(value);
                System.out.println("userinfo-api用户基本信息接口调用时间为" + (System.currentTimeMillis() - userinfoTime));
                values.add(userInfo);
                count.countDown();
            });
            executorService.submit(() -> {
                // 2. 再调用获取用户积分信息的接口
                long integralApiTime = System.currentTimeMillis();
                String intergral = restTemplate.getForObject("http://www.tony.com/integral-api/get?userId=" + userId,
                        String.class);
                JSONObject intergralInfo = JSONObject.parseObject(intergral);
                System.out.println("integral-api积分接口调用时间为" + (System.currentTimeMillis() - integralApiTime));
                values.add(intergralInfo);
                count.countDown();
        });

        count.await();// 等待计数器归零

        // 3. 合并为一个json对象
        JSONObject result = new JSONObject();
        for (JSONObject value : values) {
            result.putAll(value);
        }
        return result;
    }

1.5.3 Future和Callable(常用)

https://blog.csdn.net/q975583865/article/details/84951656

 

2.io

bio同步阻塞io

nio同步非阻塞io

三大核心部分: Channel(通道), Buffer(缓冲区), Selector

NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中 。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

BIO 是面向流的, NIO 是面向缓冲区的

 

Netty

是一个高性能、异步事件驱动的 NIO 框架

 Reactor线程模型,定义了accept线程组和io线程组,将通道注册到accept线程的selector上,io线程监听事件

 channel,负责socket连接和数据的处理,写入buffer

 channelPipeline职责链设计模式,事件处理机制

 ByteBuf缓冲区,传输数据

 

1.@Sharable

如果ChannelHandler被注解为 @Sharable,全局只有一个handler实例,它会被多个Channel的Pipeline共享,会被多线程并发调用,因此它不是线程安全的;如果存在跨ChannelHandler的实例级变量共享,需要特别注意,它可能不是线程安全的。

总之,只应该在确定了你的 ChannelHandler 是线程安全的时才使用@Sharable 注解 

2.发送缓冲区和接受缓冲区大小(内网)

server = new ServerBootstrap();
server.group(bossGroup, workerGroup) 
.childOption(ChannelOption.SO_RCVBUF,32*1024)
.childOption(ChannelOption.SO_SNDBUF,32*1024)

3.netty操作一些操作数据库耗时操作

再定义一个 处理数据的线程池bizGroup(操作数据库等)

private EventLoopGroup bossGroup;       // 主线程池,处理连接的线程池
private EventLoopGroup workerGroup;     // 工作线程池,处理io的线程池
private EventLoopGroup bizGroup;        // 业务线程池,处理数据的线程池
bizGroup = new NioEventLoopGroup(20,new DefaultThreadFactory("biz-thread-pool-")); //根据需要10,200 。。。
// 添加自定义的handler
pipeline.addLast(bizGroup,new ChatHandler());

4.高并发Bytebuf的复用

在责任链的最后一个Handler

// 添加自定义的handler
pipeline.addLast(new ChatHandler());

里添加

ctx.fireChannelRead(msg);

(如果使用的SimpleChannelInboundHandler,它会自动进行释放)

 

 

3.mq

3.1.rocketmq注意点

1.消息顺序性

  分为 生产者顺序发送 和 消费者顺序消费

java学习2.3.2_第2张图片

java学习2.3.2_第3张图片

2.有序消息的缺陷

java学习2.3.2_第4张图片

 


mysql事务隔离级别

未提交读(read uncommitted)、已提交读(read committed)、可重复读(repeatable read)、串行化(serializable)。

未提交读 A事务已执行,但未提交;B事务查询到A事务的更新后数据;A事务回滚;---出现脏数据

已提交读 (解决了脏读) A事务执行更新;B事务查询;A事务又执行更新;B事务再次查询时,前后两次数据不一致;---不可重复读

可重复读 (解决了不可重复读) A事务无论执行多少次,只要不提交,B事务查询值都不变;B事务仅查询B事务开始时那一瞬间的数据快照;

串行化 (解决了幻读) 不允许读写并发操作,写执行时,读必须等待;

 

  • 脏读:指一个线程中的事务读取到了另外一个线程中未提交的数据。

  • 不可重复读(虚读):指一个线程中的事务读取到了另外一个线程中提交的update的数据。

  • 幻读:指一个线程中的事务读取到了另外一个线程中提交的insert的数据。

spring事务传播性

待更~

 

 

treeset 

实现Comparable接口,并重写接口中的compareTo方法

CopyOnWriteArrayList

可一边遍历一遍删除,并发安全

 

 

 

JVM 类加载机制

加载,验证,准备,解析,初始化

双亲委派

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父 类去完成 。

保证了使用不同的类加载器最终得到的都是同样一个 Object 对象

 

 

分布式事务

1.ACP理论放弃A,CP组合最终一致性,数据库操作和发送消息绑定

2.rocketmq自带的解决方案,提取出事务管理器,个人感觉像tcc

你可能感兴趣的:(java学习2.3.2)