当前位置: 首页 > news >正文

redis加锁、解锁

在Java中,关于锁我想大家都很熟悉。在并发编程中,我们通过锁,来避免由于竞争而造成的数据不一致问题。通常,我们以synchronized 、Lock来使用它。

但是Java中的锁,只能保证在同一个JVM进程内中执行。如果在分布式集群环境下呢?

一、分布式锁
分布式锁,是一种思想,它的实现方式有很多。比如,我们将沙滩当做分布式锁的组件,那么它看起来应该是这样的:

加锁
在沙滩上踩一脚,留下自己的脚印,就对应了加锁操作。其他进程或者线程,看到沙滩上已经有脚印,证明锁已被别人持有,则等待。

解锁
把脚印从沙滩上抹去,就是解锁的过程。

锁超时
为了避免死锁,我们可以设置一阵风,在单位时间后刮起,将脚印自动抹去。

分布式锁的实现有很多,比如基于数据库、memcached、Redis、系统文件、zookeeper等。它们的核心的理念跟上面的过程大致相同。

二、redis
我们先来看如何通过单节点Redis实现一个简单的分布式锁。

1、加锁
加锁实际上就是在redis中,给Key键设置一个值,为避免死锁,并给定一个过期时间。

SET lock_key random_value NX PX 5000

值得注意的是:
random_value 是客户端生成的唯一的字符串。
NX 代表只在键不存在时,才对键进行设置操作。
PX 5000 设置键的过期时间为5000毫秒。

这样,如果上面的命令执行成功,则证明客户端获取到了锁。

2、解锁
解锁的过程就是将Key键删除。但也不能乱删,不能说客户端1的请求将客户端2的锁给删除掉。这时候random_value的作用就体现出来。

为了保证解锁操作的原子性,我们用LUA脚本完成这一操作。先判断当前锁的字符串是否与传入的值相等,是的话就删除Key,解锁成功。

if redis.call(‘get’,KEYS[1]) == ARGV[1] then
return redis.call(‘del’,KEYS[1])
else
return 0
end
3、实现
首先,我们在pom文件中,引入Jedis。在这里,笔者用的是最新版本,注意由于版本的不同,API可能有所差异。

redis.clients jedis 3.0.1 加锁的过程很简单,就是通过SET指令来设置值,成功则返回;否则就循环等待,在timeout时间内仍未获取到锁,则获取失败。

@Service
public class RedisLock {

Logger logger = LoggerFactory.getLogger(this.getClass());private String lock_key = "redis_lock"; //锁键protected long internalLockLeaseTime = 30000;//锁过期时间private long timeout = 999999; //获取锁的超时时间//SET命令的参数 
SetParams params = SetParams.setParams().nx().px(internalLockLeaseTime);@Autowired
JedisPool jedisPool;/*** 加锁* @param id* @return*/
public boolean lock(String id){Jedis jedis = jedisPool.getResource();Long start = System.currentTimeMillis();try{for(;;){//SET命令返回OK ,则证明获取锁成功String lock = jedis.set(lock_key, id, params);if("OK".equals(lock)){return true;}//否则循环等待,在timeout时间内仍未获取到锁,则获取失败long l = System.currentTimeMillis() - start;if (l>=timeout) {return false;}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}finally {jedis.close();}
}

}
解锁我们通过jedis.eval来执行一段LUA就可以。将锁的Key键和生成的字符串当做参数传进来。

/*** 解锁* @param id* @return*/
public boolean unlock(String id){Jedis jedis = jedisPool.getResource();String script ="if redis.call('get',KEYS[1]) == ARGV[1] then" +"   return redis.call('del',KEYS[1]) " +"else" +"   return 0 " +"end";try {Object result = jedis.eval(script, Collections.singletonList(lock_key), Collections.singletonList(id));if("1".equals(result.toString())){return true;}return false;}finally {jedis.close();}
}

最后,我们可以在多线程环境下测试一下。我们开启1000个线程,对count进行累加。调用的时候,关键是唯一字符串的生成。这里,笔者使用的是Snowflake算法。

@Controller
public class IndexController {

@Autowired
RedisLock redisLock;int count = 0;@RequestMapping("/index")
@ResponseBody
public String index() throws InterruptedException {int clientcount =1000;CountDownLatch countDownLatch = new CountDownLatch(clientcount);ExecutorService executorService = Executors.newFixedThreadPool(clientcount);long start = System.currentTimeMillis();for (int i = 0;i<clientcount;i++){executorService.execute(() -> {//通过Snowflake算法获取唯一的ID字符串String id = IdUtil.getId();try {redisLock.lock(id);count++;}finally {redisLock.unlock(id);}countDownLatch.countDown();});}countDownLatch.await();long end = System.currentTimeMillis();logger.info("执行线程数:{},总耗时:{},count数为:{}",clientcount,end-start,count);return "Hello";
}

}
至此,单节点Redis的分布式锁的实现就已经完成了。比较简单,但是问题也比较大,最重要的一点是,锁不具有可重入性。

三、redisson
Redisson是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。充分的利用了Redis键值数据库提供的一系列优势,基于Java实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。

相对于Jedis而言,Redisson强大的一批。当然了,随之而来的就是它的复杂性。它里面也实现了分布式锁,而且包含多种类型的锁,更多请参阅分布式锁和同步器

1、可重入锁
上面我们自己实现的Redis分布式锁,其实不具有可重入性。那么下面我们先来看看Redisson中如何调用可重入锁。

在这里,笔者使用的是它的最新版本,3.10.1。

org.redisson redisson 3.10.1 首先,通过配置获取RedissonClient客户端的实例,然后getLock获取锁的实例,进行操作即可。

public static void main(String[] args) {

Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
config.useSingleServer().setPassword("redis1234");final RedissonClient client = Redisson.create(config);  
RLock lock = client.getLock("lock1");try{lock.lock();
}finally{lock.unlock();
}

}
2、获取锁实例
我们先来看RLock lock = client.getLock(“lock1”); 这句代码就是为了获取锁的实例,然后我们可以看到它返回的是一个RedissonLock对象。

public RLock getLock(String name) {
return new RedissonLock(connectionManager.getCommandExecutor(), name);
}
在RedissonLock构造方法中,主要初始化一些属性。

public RedissonLock(CommandAsyncExecutor commandExecutor, String name) {
super(commandExecutor, name);
//命令执行器
this.commandExecutor = commandExecutor;
//UUID字符串
this.id = commandExecutor.getConnectionManager().getId();
//内部锁过期时间
this.internalLockLeaseTime = commandExecutor.
getConnectionManager().getCfg().getLockWatchdogTimeout();
this.entryName = id + “:” + name;
}
3、加锁
当我们调用lock方法,定位到lockInterruptibly。在这里,完成了加锁的逻辑。

public void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {

//当前线程ID
long threadId = Thread.currentThread().getId();
//尝试获取锁
Long ttl = tryAcquire(leaseTime, unit, threadId);
// 如果ttl为空,则证明获取锁成功
if (ttl == null) {return;
}
//如果获取锁失败,则订阅到对应这个锁的channel
RFuture<RedissonLockEntry> future = subscribe(threadId);
commandExecutor.syncSubscription(future);try {while (true) {//再次尝试获取锁ttl = tryAcquire(leaseTime, unit, threadId);//ttl为空,说明成功获取锁,返回if (ttl == null) {break;}//ttl大于0 则等待ttl时间后继续尝试获取if (ttl >= 0) {getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);} else {getEntry(threadId).getLatch().acquire();}}
} finally {//取消对channel的订阅unsubscribe(future, threadId);
}
//get(lockAsync(leaseTime, unit));

}
如上代码,就是加锁的全过程。先调用tryAcquire来获取锁,如果返回值ttl为空,则证明加锁成功,返回;如果不为空,则证明加锁失败。这时候,它会订阅这个锁的Channel,等待锁释放的消息,然后重新尝试获取锁。流程如下:

获取锁

获取锁的过程是怎样的呢?接下来就要看tryAcquire方法。在这里,它有两种处理方式,一种是带有过期时间的锁,一种是不带过期时间的锁。

private RFuture tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {

//如果带有过期时间,则按照普通方式获取锁
if (leaseTime != -1) {return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
}//先按照30秒的过期时间来执行获取锁的方法
RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(),TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);//如果还持有这个锁,则开启定时任务不断刷新该锁的过期时间
ttlRemainingFuture.addListener(new FutureListener<Long>() {@Overridepublic void operationComplete(Future<Long> future) throws Exception {if (!future.isSuccess()) {return;}Long ttlRemaining = future.getNow();// lock acquiredif (ttlRemaining == null) {scheduleExpirationRenewal(threadId);}}
});
return ttlRemainingFuture;

}
接着往下看,tryLockInnerAsync方法是真正执行获取锁的逻辑,它是一段LUA脚本代码。在这里,它使用的是hash数据结构。

RFuture tryLockInnerAsync(long leaseTime, TimeUnit unit,
long threadId, RedisStrictCommand command) {

    //过期时间internalLockLeaseTime = unit.toMillis(leaseTime);return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,//如果锁不存在,则通过hset设置它的值,并设置过期时间"if (redis.call('exists', KEYS[1]) == 0) then " +"redis.call('hset', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +//如果锁已存在,并且锁的是当前线程,则通过hincrby给数值递增1"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +//如果锁已存在,但并非本线程,则返回过期时间ttl"return redis.call('pttl', KEYS[1]);",Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}

这段LUA代码看起来并不复杂,有三个判断:

通过exists判断,如果锁不存在,则设置值和过期时间,加锁成功
通过hexists判断,如果锁已存在,并且锁的是当前线程,则证明是重入锁,加锁成功
如果锁已存在,但锁的不是当前线程,则证明有其他线程持有锁。返回当前锁的过期时间,加锁失败

加锁成功后,在redis的内存数据中,就有一条hash结构的数据。Key为锁的名称;field为随机字符串+线程ID;值为1。如果同一线程多次调用lock方法,值递增1。

127.0.0.1:6379> hgetall lock1

  1. “b5ae0be4-5623-45a5-8faa-ab7eb167ce87:1”
  2. “1”
    4、解锁
    我们通过调用unlock方法来解锁。

public RFuture unlockAsync(final long threadId) {
final RPromise result = new RedissonPromise();

//解锁方法
RFuture<Boolean> future = unlockInnerAsync(threadId);future.addListener(new FutureListener<Boolean>() {@Overridepublic void operationComplete(Future<Boolean> future) throws Exception {if (!future.isSuccess()) {cancelExpirationRenewal(threadId);result.tryFailure(future.cause());return;}//获取返回值Boolean opStatus = future.getNow();//如果返回空,则证明解锁的线程和当前锁不是同一个线程,抛出异常if (opStatus == null) {IllegalMonitorStateException cause = new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "+ id + " thread-id: " + threadId);result.tryFailure(cause);return;}//解锁成功,取消刷新过期时间的那个定时任务if (opStatus) {cancelExpirationRenewal(null);}result.trySuccess(null);}
});return result;

}
然后我们再看unlockInnerAsync方法。这里也是一段LUA脚本代码。

protected RFuture unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, EVAL,

        //如果锁已经不存在, 发布锁释放的消息"if (redis.call('exists', KEYS[1]) == 0) then " +"redis.call('publish', KEYS[2], ARGV[1]); " +"return 1; " +"end;" +//如果释放锁的线程和已存在锁的线程不是同一个线程,返回null"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +"return nil;" +"end; " +//通过hincrby递减1的方式,释放一次锁//若剩余次数大于0 ,则刷新过期时间"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +"if (counter > 0) then " +"redis.call('pexpire', KEYS[1], ARGV[2]); " +"return 0; " +//否则证明锁已经释放,删除key并发布锁释放的消息"else " +"redis.call('del', KEYS[1]); " +"redis.call('publish', KEYS[2], ARGV[1]); " +"return 1; "+"end; " +"return nil;",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));

}
如上代码,就是释放锁的逻辑。同样的,它也是有三个判断:

如果锁已经不存在,通过publish发布锁释放的消息,解锁成功

如果解锁的线程和当前锁的线程不是同一个,解锁失败,抛出异常

通过hincrby递减1,先释放一次锁。若剩余次数还大于0,则证明当前锁是重入锁,刷新过期时间;若剩余次数小于0,删除key并发布锁释放的消息,解锁成功

至此,Redisson中的可重入锁的逻辑,就分析完了。但值得注意的是,上面的两种实现方式都是针对单机Redis实例而进行的。如果我们有多个Redis实例,请参阅Redlock算法。该算法的具体内容,请参考http://redis.cn/topics/distlock.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-35129.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

atcoder arc 122 a~b题Many Formulae、Insurance

A题链接 题目大意&#xff1a;不能存在两个及两个以上的减号&#xff0c;所有满足条件的式子之和。 题目思路&#xff1a;当时考试想到一半&#xff0c;就感觉编码能力不太会&#xff0c;然后就没做&#xff0c; 首先我们定义dp[N][2]&#xff0c;这种选或不选的问题&#xff0…...

【pandas】根据其他表格列数据更新相应的列字段,apply()操作实例

今天在学习中&#xff0c;遇到一个小问题&#xff0c;需要把主表中的出行网格id&#xff0c;和终点网格id替换成对应的枢纽地点&#xff0c;从表中有每个枢纽对应的id&#xff08;一个枢纽对应多个网格id&#xff09; 1.原始数据如下图 上面是枢纽id,下方是出行信息 2.将数…...

数据库课程设计 大学生综合管理系统

问题描述&#xff1a; 设计并开发一套完整的在校大学生学习的综合管理系统&#xff0c;其中可包括以下几个模块&#xff1a; &#xff08;一&#xff09;选课管理&#xff1a;该系统包括教师、学生、系、课程和教室等信息&#xff0c;基本情况如下&#xff1a; 教师有工作证号…...

No qualifying bean of type ‘com.kkb.dao.*Mapper‘ available

没有查找到 *mapper对象程序报错没有查找到 mapper对象 可能造成的原因&#xff1a;缺少相应的注解 在SpringBoot的启动类中缺少 MapperScan SpringBootApplication MapperScan("com.yhp.dao") public class Application {public static void main(String[] args) …...

WPF 简单使用keybd_event模拟触发键盘

主要是添加Win32函数 其次是定义键盘按下&#xff0c;抬起的两个固定值。 [DllImport("User32.dll")]public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);/// <summary>/// 按下/// </summary>const int KEY…...

java程序员日常工作内容,Java面试题及解析

目录 Kafka的基本介绍Kafka的设计原理分析Kafka数据传输的事务特点Kafka消息存储格式副本&#xff08;replication&#xff09;策略Kafka消息分组&#xff0c;消息消费原理Kafak顺序写入与数据读取消费者&#xff08;读取数据&#xff09; Kafka的基本介绍 Kafka是最初由Lin…...

常用网络数据包丢失的分析与处理

网络管理维护过程中&#xff0c;经常会遇到数据包丢失的情况。用Ping命令进行连接测试&#xff0c;会发现Ping包的延迟远远超过正常值&#xff0c;甚至无法到达&#xff0c;同时伴随着网络服务应用的障碍&#xff0c;比如打开网站的速度太慢&#xff0c;严重时甚至无法打开网页…...

2021-06-23 SpringCloud Zuul网关filter添加或修改传递的参数

场景&#xff1a;通过网关转发服务到具体的ip地址 比如网关验证accessToken&#xff0c;需要拦截访问&#xff0c;然后在url中添加参数&#xff0c;如下 //1、这个是原来的参数数据 String accessToken request.getParameter("accessToken"); //2、转换后的数据 S…...

面试笔试题

1.src和href的区别 &#xff1f; 答:src用于替代当前的元素&#xff0c;而href用于建立这个标签与外部资源之间的关系。 href 是Hypertext Reference的简写&#xff0c;表示超文本引用&#xff0c;指向网络资源所在位置。 常用场景: <a href"http://www.baidu.com&…...

MySQL下载及配置过程

MySQL下载及配置过程 下载&#xff08;Windows&#xff09; 下载地址 https://dev.mysql.com/downloads/mysql/ 进入后的界面&#xff0c;点击Download下载。 点击Download进入此界面&#xff0c;点击标注的地方直接下载。 配置 这里只介绍 .zip 格式。 .zip格式不需要…...

DQL查询数据(最重点)

4、DQL查询数据&#xff08;最重点&#xff09; 4.1、DQL &#xff08;Data query Language&#xff1a;数据查询语言&#xff09; 所有的查询操作都用它 Select简单的查询&#xff0c;复杂的查询它都能做数据库中最核心的语言&#xff0c;最重要的语句使用频率最高的语句 …...

Redis之三种特殊数据类型

该笔记大部分搬运B站遇见狂神说的Redis&#xff0c;顺便把图文合并记录&#xff0c;便于回顾&#xff0c;仅用于学习&#xff01; 视频地址&#xff1a;https://www.bilibili.com/video/BV1S54y1R7SB?t250 作者真的非常好&#xff0c;记得三连 如有侵权&#xff0c;请联系删除…...

面向对象 实验4

实验四 对象作为数据成员 1 实验目的 学习对象作为类的数据成员的使用方法&#xff0c;学习对象数据成员的初始化以及“成员初始化器”的使用方法。 2 实验内容 2.1 使用Date类&#xff0c;定义Employee类 问题描述 在《实验三 面向对象初步》中&#xff0c;设计了日期类…...

闭关5个月,终于把这篇阿里P8大牛的数据结构与算法领悟明白!!以入阿里!!

数据结构是计算机科学与技术专业非常重要的-一门核心基础课&#xff0c;计算机科学各个领域及各种应用软件都要使用相关的数据结构和算法。 经历过校招的人都知道&#xff0c;算法和数据结构都是不可避免的。像拼多多、头条这种大公司&#xff0c;上来就来几道算法题&#xff…...

安卓按键响应的方式

一、在xml中设置按键的onClick绑定的函数 在页面显示两个按钮,用onClick 绑定buttonBeClicked函数&#xff0c;该函数在MainActivity.java中实现。 activity.main.xml: <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools…...

实战篇:sdram+fifo调试

本片主要总结SDRAM的FIFO优化仿真中出现的问题及解析。 针对下图的疑问点&#xff1a; 1.图中第一处&#xff0c;SDRAM的数据线在写FIFO往SDRAM写的过程中位高阻态&#xff0c;但实际应该是wr_data才对。为何&#xff1f; 在代码中&#xff0c;关于DQ以及ADDR的PIN定义没有位…...

组队学习:学习者参考手册

学习者参考手册 作为希望参与组队学习活动的学习者&#xff0c;一定想了解有关本次活动的各种环节。我就通过这份手册来给大家介绍一下。 本手册一共分为四个部分&#xff0c;分别是活动角色划分&#xff0c;活动流程介绍、打卡环节介绍、角色职责介绍。 1. 大航海模型 航路…...

2021-07-9 unity学习笔记(25)之插件Dialogue System for Unity的使用注意事项

2021-07-9 unity学习笔记(25)之插件Dialogue System for Unity的使用注意事项 要在玩家身上挂selector组件&#xff0c;在需要对话的对象上挂usable组件&#xff0c;usable组件中的max use distance要设置到能让鼠标射线检测到得范围&#xff0c;同时要在对话的对象上挂碰撞器…...

ubuntu20 ros darknet 安装记录

1. 代码下载 代码Github主页&#xff1a;https://github.com/leggedrobotics/darknet_ros 下载命令&#xff1a; mkdir -p catkin_workspace/srccd catkin_workspace/srcgit clone --recursive gitgithub.com:leggedrobotics/darknet_ros.gitcd ../不知道怎么git clone的朋友可…...

Jmeter接口测试提取token值为全局变量

jmeter接口测试提取token值为全局变量有两种常用方法&#xff1a;正则表达式提取器、JSON提取器。 PS:例如返回数据如下&#xff0c;下面的操作都根据此次返回数据进行&#xff1a; {data{"file1": "value1","file2": "value2","…...

Vue 路由导航

...

浮动布局,定位布局,伸缩盒布局

布局 默认文档流 1.元素显示的顺序和代码的顺序是一致的 2.块级元素独占一行空间&#xff0c;默认宽度为父元素的100%&#xff0c;高度由内容或者子元素决定 3.行内元素共享一行空间&#xff0c;默认宽高都由内容决定 浮动布局 float&#xff08;如果一个元…...

齐发78EX重大事件|荣获美国加拿大双国MSB牌照

齐发78EX LTD在2021年7月已同时获得美国及加拿大MSB合规运营牌照&#xff0c;标志着齐发78EX全球合规化的布局已经进入了一个新阶段。未来&#xff0c;齐发78EX也将继续致力于全球和规划进程的推进&#xff0c;面对全球化唯一的道路就是进一步获得全球投资者的信任&#xff0c;…...

vue如何实现数据双向绑定,我的阿里手淘面试经历分享,看这篇文章准没错!

前言 全网唯一一份&#xff0c;对标阿里P7年薪60w的Android高级工程师学习进阶路线&#xff08;图未完全展开&#xff0c;怕大家看不清楚&#xff09;&#xff1a; 本篇文章都会围绕这份脑图来写&#xff0c;详细的介绍你处于哪个阶段该如何进阶&#xff0c;以及年薪层次高低对…...

leetcode 236. 二叉树的最近公共祖先

题目来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode-cn.com/problems 特别鸣谢&#xff1a;来自夸夸群的 醉笑陪公看落花知乎&#xff0c;王不懂不懂知乎&#xff0c;QFIUNEcsdn 感谢醉笑陪公看落花知乎 倾囊相授&#xff0c;感谢小伙…...

弘辽科技:成为拼多多商家要什么要求?收费吗?

现在也有不少人想要入驻拼多多&#xff0c;但是想要成为拼多多的商家也需要满足对应的要求&#xff0c;同时也想要了解成为拼多多商家是否需要收费&#xff0c;我马上就来给各位卖家们介绍。 拼多多商家入驻平台分四种店铺&#xff0c;这里小编介绍一下旗舰店、专营店入驻基本条…...

辗转相除求最大公约数

#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>int main() {int a 0;int b 0;int tmp 0;scanf("%d %d", &a, &b);if (a < b){tmp a;a b;b tmp;}if (a%b ! 0){tmp a;a b;b tmp%b;}printf("%d\n", b);return 0; }...

K-means笔记

K-means算法 算法过程&#xff1a; 从N个样本数据中随机选取K个对象作为初始的聚类中心。分别计算每个样本到这各个聚类中心的距离&#xff0c;并将对象归于距离最短的聚类群中。所有样本计算完后&#xff0c;重新计算K个聚类中心。与前一次计算得到得聚类中心比较。如果聚类中…...

39.【Axure 10 】交元件(元件组)交互事件

鼠标相关交互事件 【高】单击时 元件(元件组)的是鼠标单击事件&#xff0c;可以实现鼠标单击的触发的交互事件。 【中】双击事件 元件(元件组)的是鼠标双击事件&#xff0c;作为触发条件。同时也是双击页面任何地方可触发。 【中】鼠标右击事件 元件(元件组)的鼠标右击是…...

hive常用函数

1. 获取某个字段的值 regexp_extract(message, (.*?)properties(.*?),, 2) as value 2....

北工大计算机学院导师选择,导师信息#北工大计算机学院计算机科学与技术导师介绍#高红雨...

一、基本情况姓名&#xff1a;高红雨性别&#xff1a;男部门&#xff1a;计算机学院软件学科部职称&#xff1a;副教授二、主要研究方向软件自动化三、在研课题北京市自然科学基金项目“面向GML数据集成的通用查询语言及实现方法的研究”(成员)四、科研成果科研项目&#xff1a…...

合肥工大计算机等级考试报名,合肥工大2013年下半年计算机等级考试报名时间...

关于2013年(下)等级考试报名通知各位同学&#xff1a;一、2013年(下)第38次全国计算机等级考试报名将于6月19日开始。教育部考试中心从本次考试开始对全国计算机等级考试的考试体系进行了重大调整&#xff0c;考试科目、考核内容和考试形式都有较大改革。今年下半年将实施2013版…...

湖工大计算机网络试卷,安工大计算机网络试卷A

安工大计算机网络试卷装 订 线课程________________________班级________________________姓名__________________________学号________________________密 封 线 安题号 得分一 二 三 四 五徽六 七工八业九大十 十一学十二试十三题十四 十五纸(一)十六 十七 十八 十九 二十 总…...

创建三个并发进程linux,实验三Linux进程并发程序设计

《实验三Linux进程并发程序设计》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《实验三Linux进程并发程序设计(6页珍藏版)》请在人人文库网上搜索。1、湖北工业大学工程技术学院实验报告课程名称&#xff1a;操作系统实验内容&#xff1a;实验三Linux进程并发程序设计…...

大数据python入门 合肥工业大学 翡翠湖_python实现合工大试题库自动刷题

1 #coding utf-82 importre3 importrequests4 importxlrd56 save_url "http://tkkc.hfut.edu.cn/student/exam/manageExam.do?1479131327464&methodsaveAnswer"7 #index用于提示题目序号8 index 19 headers {"User-Agent": "Mozilla/5.0 (Win…...

湖北工业大学计算机学院考研资料,湖北工业大学计算机学院836数据结构历年考研真题汇编.pdf...

目 录2008 年湖北工业大学计算机学院 917 数据结构历年考研真题汇编考研真题 22007 年湖北工业大学计算机学院 440 数据结构历年考研真题汇编考研真题 112006 年湖北工业大学计算机学院 409 数据结构历年考研真题汇编考研真题 162005 年湖北工业大学计算机学院 409 数据结构历年…...

计算机网络笔记(湖科大)_ Part 02 物理层

文章参考于B站&#xff1a;计算机网络微课堂 二、物理层 1、基本概念 2、传输媒体 2.1导引型传输媒体 同轴电缆 双绞线 光纤 电力线 2.2非导引型传输媒体 感兴趣的话可以去了解 无线电波微波红外线可见光 3、传输方式 串行 &#xff1a;2台计算机之间的网络通信&#xff0…...

湖工大11级c语言网,湖南工大11级C语言网上作业之《运算符与表达式》

湖南工大11级C语言网上作业之《运算符与表达式》《程序设计语言 C1》随机作业题做作业时间&#xff1a;2012-3-8 8:00:00至2012-5-29 23:30:001、若希望当A的值为奇数时&#xff0c;表达式的值为“真”&#xff0c;A的值为偶数时&#xff0c;表达式的值为“假”&#xff0c;则以…...

计算机网络基础知识点(七层协议)

七层协议 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。 每一层的作用和理解 1. 物理层&#xff1a;RJ45、CLOCK、IEEE802.3 &#xff08;中继器&#xff0c;集线器&#xff0c;网关&#xff09; 解决两个硬件之间怎么通信。俩个硬件进行比特流的发送和接受…...

湖北工业大学计算机网络教学平台,刘伟-欢迎访问湖北工业大学计算机学院官方网站...

科研情况介绍(研究方向、研究课题、现正进行的科研项目)研究方向&#xff1a;数字图像处理(生物图像、有机材料图像的处理与识别)RFID(传感器网络)主要的课题研究说明&#xff1a;1)有机材料图像的处理与识别课题以含大掺量矿物掺合料复合胶凝材料为研究对象&#xff0c;借助复…...

湖北工业大学计算机考研资料汇总

湖北工业大学研招网 http://yjs.hbut.edu.cn/ 湖北工业大学计算机学院 http://jsjxy.hbut.edu.cn/ 湖北工业大学&#xff08;Hubei University of Technology&#xff09;&#xff0c;简称“湖工大”&#xff0c;坐落在有“九省通衢”之称的国家中心城市——武汉&#xff0…...

湖工大c语言题库,湖 南 大 学C语言程序代码.doc

湖 南 大 学C语言程序代码湖 南 大 学C语言实训课程序设计------贪吃蛇院(系)&#xff1a; 电气与信息工程学院专业班级&#xff1a; 测控技术与仪器1102班学 号&#xff1a; 20110704203学生姓名&#xff1a; 晁涛涛贪吃蛇游戏程序设计一、课程设计任务贪吃蛇小游戏程序设计二…...

湖北工业大学深澜校园网断线自动重连

一、采集自己的登录信息 1、在湖工大校园网登录页面点击F12&#xff0c;进入开发者选项。 2、自行输入账号密码&#xff0c;点击连接&#xff1b;在网络标头中找到如下的记录。这都是代码中需要的修改值。 二、将自己的登录信息输入到代码中 代码如下&#xff08;示例&#xf…...

湖南工业大学python题库_2019年下半年“全国计算机等级考试”湖工大考点报名通知...

2019年下半年56次“全国计算机等级考试”(简称NCRE)将于2019年9月21-23日举行&#xff0c;考生统一使用教育部考试中心的网上报名系统进行注册报名、缴费及准考证的自助打印&#xff0c;现将报考有关事项通知如下&#xff1a;一 、开考科目二级&#xff1a;C语言程序设计、VB语…...

【杂谈】感谢母校湖工大

本博客还有大量的.NET开源技术文章&#xff0c;您可能感兴趣&#xff1a; 1.开源Math.NET基础数学类库使用系列文章&#xff1a;链接 2.开源C#彩票数据资料库系列文章&#xff1a;链接 3.开源的.NET平台ORM组件文章&#xff1a;链接 4.其他开源的.NET组件文章&#xff1a;链接…...

简单的数据库课程设计----湖工大成绩管理系统

&#xfeff;&#xfeff;大二下的数据库课程设计&#xff0c;设计一个简单的成绩管理数据库系统。这门课的老师康老师&#xff0c;是个很好的女老师&#xff0c;人很温和&#xff0c;上课很认真&#xff0c;几乎每节课都会提前上课帮大家复习一下上节课的内容。上课的内容也不…...

字符数组(湖工大)

第1关&#xff1a;字符逆序 100 任务要求评论973 任务描述相关知识&#xff08;略&#xff09;编程要求测试说明任务描述 题目描述:输入一个字符串&#xff0c;输出反序后的字符串。 相关知识&#xff08;略&#xff09; 编程要求 请仔细阅读右侧代码&#xff0c;结合相关…...

函数(湖工大)

第1关&#xff1a;求和 任务描述 题目描述:给你一个n&#xff0c;要求你编写一个函数求12.......n. 相关知识&#xff08;略&#xff09; 编程要求 请仔细阅读右侧代码&#xff0c;结合相关知识&#xff0c;在Begin-End区域内进行代码补充。 输入 输入一个n 输出 输出12…...

子网掩码与VLAN有何区别?

子网掩码与VLAN有何区别?_百度知道 (baidu.com) 可以这么理解&#xff1a;子网掩码是对节省IP地址的资源而设立。而VLAN则是对方便网络管理需要而设立。两者之间似乎有相识之处&#xff0c;但各自的功能是不一样的。 vlan下起子网,子网掩码与vlan有何区别-天道酬勤-花开半夏…...

湖工大2011C语言答案,湖工大C语言题库.docx

sum ( int arr[ ],int n ){ int i,s;s 0;for ( i0; ix){s st;nn2.0;k-k;tk/n;}return s ; //程序编写部分/***********end***********/}void main(){double x,sum;printf("Enter x:\n");scanf("%lf",&x);sumfun(x);printf("sum%.4f\n",sum)…...