xxl-job、AQS

 

xxl-job  java-17

xxl-job https://mp.weixin.qq.com/s/jLoVERAeqkIiqomjN4MY7w  
代码地址 https://github.com/xuxueli/xxl-job
系统地址 http://localhost:8080/xxl-job-admin/  admin 123456

轻量级开源分布式调度框架,分为管理端和执行端两块,管理端负责配置任务信息以及查看任务执行日志,执行端只需要配置与管理端的连接信息就可以进行具体的任务逻辑开发了

多实例分布式调度任务,修改配置
server.port=
xxl.job.executor.port=

 

@Component
public class SampleXxlJob2 {
    private static Logger logger = LoggerFactory.getLogger(SampleXxlJob2.class);
    /**
     * 1、简单任务示例(Bean模式)
     */
    @XxlJob("demoJobHandlerXmh")
    public void demoJobHandler(String param) throws Exception {
        XxlJobHelper.log("xinginghui, Hello World."+param);
        logger.info("*****************xinginghui, Hello World.");
        for (int i = 0; i < 5; i++) {
            XxlJobHelper.log("beat at:" + i);
            TimeUnit.SECONDS.sleep(2);
        }
        // default success
    }
    /**
     * 2、分片广播任务
     */
    @XxlJob("shardingJobHandlerXmh")
    public void shardingJobHandlerXmh() throws Exception {
        logger.info("*****************xinginghui, Hello World.");
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();

        XxlJobHelper.log("分片参数***:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);

        // 业务逻辑
        for (int i = 0; i < shardTotal; i++) {
            if (i == shardIndex) {
                XxlJobHelper.log("第 {} 片, 命中分片开始处理", i);
            } else {
                XxlJobHelper.log("第 {} 片, 忽略", i);
            }
        }
    }

  

image

 启动多个执行器 XxlJobExecutorApplication  分布式任务执行

 分片任务,有多少个执行器实例,就有多少个分片,把100条数据分为10份由10个实例同时执行

 

 

 

 

synchronized
1,获取不到锁-等待 其他线程释放锁(被锁代码执行完或者wait) 本线程参与竞争锁
2,获取到锁 wait(释放锁,其他线程继续竞争) 其他线程通知notifyAll 本线程参与竞争锁 获取锁成功继续执行业务

ReentrantLock
1,相同的ReentrantLock对象,多线程竞争获取锁
2,使用condition来wait挂起线程释放锁 其他线程继续竞争锁 其他线程通过condition.signal()来通知相同condition的线程来获取锁,以此达到分组通知的目的 每个线程传入不通的condition来condition.await()及signal
3,可实现公平锁和非公平锁
4,使用起来更加灵活,lock.lock()获取锁,获取不到-等待,类似synchronize tryLock能获得锁就返回true,不能就立即返回false
5,提供了线程中断机制 lockInterruptibly() interrupt()

AbstractQueuedSynchronizer
1,AQS定义了一套多线程访问共享资源的同步器框架 是一个依赖状态(state)的同步器
维护了一个队列 一个状态值 用CAS算法尝试获取锁(修改状态值) 获取不到锁放入队列
2,
非公平锁:无论CLH队列中是否有节点,当前线程都要和队列头的节点去竞争一下锁;若竞争到锁,则该线程去持有锁;若没有竞争到锁,则放入到CLH队列尾部;
公平锁:无论CLH队列中是否有节点,当前线程都是去放到队列的尾部
3,lock获取锁机制,无限循环+CAS操作竞争锁
当本节点的前一个节点是head时,尝试获取锁 获取成功,设置为head节点
https://www.cnblogs.com/yufeng218/p/13090453.html

通过cas操作放入队尾
Node pred = tail;
if (pred != null) {
    node.prev = pred;
    if (compareAndSetTail(pred, node)) {//尾部节点的期望值pred,更新值node 多线程竞争,期望值不匹配,继续CAS
	pred.next = node;
	return node;
    }
}

 

AS的全称是Compare-And-Swap,它是CPU并发原语。
原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致的问题,也就是说CAS是线程安全的

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

 

interrupt()  如果线程被阻塞 可实现中断处理
① 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。仅此而已。
② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。

    @Test
    public void myTest(){
        ServiceTest test = new ServiceTest();
        Thread t1 = new Thread(){
            @Override
            public void run(){
                try {
                    test.stest();
                } catch (Exception e) {
                    System.out.println("*******interrupt:"+Thread.currentThread().getName());
                }
            }
        };
        t1.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t1.interrupt();
    }

    public synchronized void stest() throws Exception {
        System.out.println("**********stest*******"+Thread.currentThread().getName());
        try {
            this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw e;
        }
        System.out.println("**********stest-end*******"+Thread.currentThread().getName());
    }


针对第二种情况,以下运行结果 false true last:false 线程执行结束后,会变回false
        System.out.println(t1.isInterrupted());
        t1.start();
        t1.interrupt();
        System.out.println(t1.isInterrupted());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("last:"+t1.isInterrupted());
 

  

ReentrantLock 线程中断  lock.lockInterruptibly();  t1.interrupt();   获取不到锁 则被中断,中断异常处理逻辑
    private Lock lock = new ReentrantLock();
    public void doBussiness() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " 开始获取锁");
        try {
            lock.lockInterruptibly();
            System.out.println(name + " 得到锁");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            System.out.println(name + " 被中断");
        } finally {
            try {
                lock.unlock();
                System.out.println(name + " 释放锁");
            } catch (Exception e) {
                System.out.println(name + " : 没有得到锁的线程运行结束");
            }
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        LockTest lockTest = new LockTest();
        Thread t0 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        lockTest.doBussiness();
                    }
                }
                );
        Thread t1 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        lockTest.doBussiness();
                    }
                }
                );
        // 启动线程t1
        t0.start();
        Thread.sleep(10);
        // 启动线程t2
        t1.start();
        Thread.sleep(5000);
        // 线程t1没有得到锁,中断t1的等待
        t1.interrupt();
    }

  

 

posted @ 2022-07-15 17:14  XUMT111  阅读(132)  评论(0)    收藏  举报