Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
晶之木
miaosha
提交
9c73ca56
M
miaosha
项目概览
晶之木
/
miaosha
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
M
miaosha
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
9c73ca56
编写于
9月 21, 2018
作者:
Q
qiurunze
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
提交threadlocal讲解
上级
133946bd
变更
17
展开全部
隐藏空白更改
内联
并排
Showing
17 changed file
with
432 addition
and
266 deletion
+432
-266
.idea/libraries/Maven__com_google_guava_guava_18_0.xml
.idea/libraries/Maven__com_google_guava_guava_18_0.xml
+13
-0
.idea/workspace.xml
.idea/workspace.xml
+283
-251
README.md
README.md
+28
-2
miaosha.iml
miaosha.iml
+1
-0
pom.xml
pom.xml
+5
-1
src/main/java/com/geekq/miaosha/DemoTask.java
src/main/java/com/geekq/miaosha/DemoTask.java
+54
-0
src/main/java/com/geekq/miaosha/Test.java
src/main/java/com/geekq/miaosha/Test.java
+15
-0
src/main/java/com/geekq/miaosha/config/UserArgumentResolver.java
...n/java/com/geekq/miaosha/config/UserArgumentResolver.java
+13
-12
src/main/java/com/geekq/miaosha/controller/MiaoshaController.java
.../java/com/geekq/miaosha/controller/MiaoshaController.java
+10
-0
src/main/java/com/geekq/miaosha/controller/RateLimiterController.java
...a/com/geekq/miaosha/controller/RateLimiterController.java
+10
-0
target/classes/com/geekq/miaosha/DemoTask$1.class
target/classes/com/geekq/miaosha/DemoTask$1.class
+0
-0
target/classes/com/geekq/miaosha/DemoTask$2.class
target/classes/com/geekq/miaosha/DemoTask$2.class
+0
-0
target/classes/com/geekq/miaosha/DemoTask.class
target/classes/com/geekq/miaosha/DemoTask.class
+0
-0
target/classes/com/geekq/miaosha/Test.class
target/classes/com/geekq/miaosha/Test.class
+0
-0
target/classes/com/geekq/miaosha/config/UserArgumentResolver.class
...asses/com/geekq/miaosha/config/UserArgumentResolver.class
+0
-0
target/classes/com/geekq/miaosha/controller/MiaoshaController.class
...sses/com/geekq/miaosha/controller/MiaoshaController.class
+0
-0
target/classes/com/geekq/miaosha/controller/RateLimiterController.class
.../com/geekq/miaosha/controller/RateLimiterController.class
+0
-0
未找到文件。
.idea/libraries/Maven__com_google_guava_guava_18_0.xml
0 → 100644
浏览文件 @
9c73ca56
<component
name=
"libraryTable"
>
<library
name=
"Maven: com.google.guava:guava:18.0"
>
<CLASSES>
<root
url=
"jar://$MAVEN_REPOSITORY$/com/google/guava/guava/18.0/guava-18.0.jar!/"
/>
</CLASSES>
<JAVADOC>
<root
url=
"jar://$MAVEN_REPOSITORY$/com/google/guava/guava/18.0/guava-18.0-javadoc.jar!/"
/>
</JAVADOC>
<SOURCES>
<root
url=
"jar://$MAVEN_REPOSITORY$/com/google/guava/guava/18.0/guava-18.0-sources.jar!/"
/>
</SOURCES>
</library>
</component>
\ No newline at end of file
.idea/workspace.xml
浏览文件 @
9c73ca56
此差异已折叠。
点击以展开。
README.md
浏览文件 @
9c73ca56
...
...
@@ -92,7 +92,33 @@ redis的数量不是库存,他的作用仅仅只是为了阻挡多余的请求
1.
具体我会有时间更新关于redis的知识
### <font color=#0099ff size=3 >15.rabbitmq如何做到消息不重复不丢失即使服务器重启?</font><br>
1.
exchange持久化2.queue持久化3.发送消息设置MessageDeliveryMode.persisent这个也是默认的行为4.手动确认
1.
exchange持久化2.queue持久化3.发送消息设置MessageDeliveryMode.persisent这个也是默认的行为4.手动确认
\ No newline at end of file
### <font color=#0099ff size=3 >15.为什么threadlocal存储user对象,原理??</font><br>
![
整体流程
](
http://i2.bvimg.com/601558/3293e36cc2c7e303.png
)
1.
并发编程中重要的问题就是数据共享,当你在一个线程中改变任意属性时,所有的线程都会因此受到影响,同时会看到第一个线程修改后的值
<br>
有时我们希望如此,比如:多个线程增大或减小同一个计数器变量
<br>
但是,有时我们希望确保每个线程,只能工作在它自己的线程实例的拷贝上,同时不会影响其他线程的数据
<br>
举例: 举个例子,想象你在开发一个电子商务应用,你需要为每一个控制器处理的顾客请求,生成一个唯一的事务ID,同时将其传到管理器或DAO的业务方法中,以便记录日志。一种方案是将事务ID作为一个参数,传到所有的业务方法中。但这并不是一个好的方案,它会使代码变得冗余。
你可以使用ThreadLocal类型的变量解决这个问题。首先在控制器或者任意一个预处理器拦截器中生成一个事务ID
然后在ThreadLocal中 设置事务ID,最后,不论这个控制器调用什么方法,都能从threadlocal中获取事务ID
而且这个应用的控制器可以同时处理多个请求,
同时在框架 层面,因为每一个请求都是在一个单独的线程中处理的,所以事务ID对于每一个线程都是唯一的,而且可以从所有线程的执行路径获取
运行结果可以看出每个线程都在维护自己的变量:
Starting Thread: 0 : Fri Sep 21 23:05:34 CST 2018
<br>
Starting Thread: 2 : Fri Sep 21 23:05:34 CST 2018
<br>
Starting Thread: 1 : Fri Jan 02 05:36:17 CST 1970
<br>
Thread Finished: 1 : Fri Jan 02 05:36:17 CST 1970
<br>
Thread Finished: 0 : Fri Sep 21 23:05:34 CST 2018
<br>
Thread Finished: 2 : Fri Sep 21 23:05:34 CST 2018
<br>
局部线程通常使用在这样的情况下,当你有一些对象并不满足线程安全,但是你想避免在使用synchronized关键字
<br>
块时产生的同步访问,那么,让每个线程拥有它自己的对象实例
<br>
注意:局部变量是同步或局部线程的一个好的替代,它总是能够保证线程安全。唯一可能限制你这样做的是你的应用设计约束
<br>
所以设计threadlocal存储user不会对对象产生影响,每次进来一个请求都会产生自身的线程变量来存储
\ No newline at end of file
miaosha.iml
浏览文件 @
9c73ca56
...
...
@@ -49,6 +49,7 @@
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-context:4.3.12.RELEASE"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-webmvc:4.3.12.RELEASE"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework:spring-expression:4.3.12.RELEASE"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: com.google.guava:guava:18.0"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.springframework.boot:spring-boot-starter-thymeleaf:1.5.8.RELEASE"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.thymeleaf:thymeleaf-spring4:2.1.5.RELEASE"
level=
"project"
/>
<orderEntry
type=
"library"
name=
"Maven: org.thymeleaf:thymeleaf:2.1.5.RELEASE"
level=
"project"
/>
...
...
pom.xml
浏览文件 @
9c73ca56
...
...
@@ -24,7 +24,11 @@
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<dependency>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava
</artifactId>
<version>
18.0
</version>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-thymeleaf
</artifactId>
...
...
src/main/java/com/geekq/miaosha/DemoTask.java
0 → 100644
浏览文件 @
9c73ca56
package
com.geekq.miaosha
;
import
java.util.Date
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicInteger
;
public
class
DemoTask
implements
Runnable
{
// Atomic integer containing the next thread ID to be assigned
private
static
final
AtomicInteger
nextId
=
new
AtomicInteger
(
0
);
// Thread local variable containing each thread's ID
private
static
final
ThreadLocal
<
Integer
>
threadId
=
new
ThreadLocal
<
Integer
>()
{
@Override
protected
Integer
initialValue
()
{
return
nextId
.
getAndIncrement
();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public
int
getThreadId
()
{
return
threadId
.
get
();
}
// Returns the current thread's starting timestamp
private
static
final
ThreadLocal
<
Date
>
startDate
=
new
ThreadLocal
<
Date
>()
{
protected
Date
initialValue
()
{
if
(
threadId
.
get
()==
1
){
return
new
Date
(
77777777L
);
}
return
new
Date
();
}
};
@Override
public
void
run
()
{
System
.
out
.
printf
(
"Starting Thread: %s : %s\n"
,
getThreadId
(),
startDate
.
get
());
try
{
TimeUnit
.
SECONDS
.
sleep
((
int
)
Math
.
rint
(
Math
.
random
()
*
10
));
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
System
.
out
.
printf
(
"Thread Finished: %s : %s\n"
,
getThreadId
(),
startDate
.
get
());
}
}
\ No newline at end of file
src/main/java/com/geekq/miaosha/Test.java
0 → 100644
浏览文件 @
9c73ca56
package
com.geekq.miaosha
;
public
class
Test
{
public
static
void
main
(
String
[]
args
)
{
DemoTask
demoTask
=
new
DemoTask
();
DemoTask
demoTask1
=
new
DemoTask
();
DemoTask
demoTask2
=
new
DemoTask
();
Thread
t
=
new
Thread
(
demoTask
);
t
.
start
();
new
Thread
(
demoTask
).
start
();
new
Thread
(
demoTask2
).
start
();
}
}
src/main/java/com/geekq/miaosha/config/UserArgumentResolver.java
浏览文件 @
9c73ca56
package
com.geekq.miaosha.config
;
import
com.geekq.miaosha.access.UserContext
;
import
com.geekq.miaosha.domain.MiaoshaUser
;
import
com.geekq.miaosha.service.MiaoShaUserService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.stereotype.Service
;
...
...
@@ -13,7 +13,6 @@ import org.springframework.web.method.support.ModelAndViewContainer;
import
javax.servlet.http.Cookie
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
@Service
public
class
UserArgumentResolver
implements
HandlerMethodArgumentResolver
{
...
...
@@ -28,16 +27,18 @@ public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public
Object
resolveArgument
(
MethodParameter
methodParameter
,
ModelAndViewContainer
modelAndViewContainer
,
NativeWebRequest
webRequest
,
WebDataBinderFactory
webDataBinderFactory
)
throws
Exception
{
HttpServletRequest
request
=
webRequest
.
getNativeRequest
(
HttpServletRequest
.
class
);
HttpServletResponse
response
=
webRequest
.
getNativeResponse
(
HttpServletResponse
.
class
);
String
paramToken
=
request
.
getParameter
(
MiaoShaUserService
.
COOKIE_NAME_TOKEN
);
String
cookieToken
=
getCookieValue
(
request
,
MiaoShaUserService
.
COOKIE_NAME_TOKEN
);
if
(
StringUtils
.
isEmpty
(
cookieToken
)
&&
StringUtils
.
isEmpty
(
paramToken
))
{
return
null
;
}
String
token
=
StringUtils
.
isEmpty
(
paramToken
)?
cookieToken:
paramToken
;
return
userService
.
getByToken
(
response
,
token
);
// HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
// HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
//
// String paramToken = request.getParameter(MiaoShaUserService.COOKIE_NAME_TOKEN);
// String cookieToken = getCookieValue(request, MiaoShaUserService.COOKIE_NAME_TOKEN);
// if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
// return null;
// }
// String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
// return userService.getByToken(response, token);
//threadlocal 存储线程副本 保证线程不冲突
return
UserContext
.
getUser
();
}
private
String
getCookieValue
(
HttpServletRequest
request
,
String
cookiName
)
{
...
...
src/main/java/com/geekq/miaosha/controller/MiaoshaController.java
浏览文件 @
9c73ca56
...
...
@@ -66,12 +66,22 @@ public class MiaoshaController implements InitializingBean {
return
Result
.
error
(
CodeMsg
.
SESSION_ERROR
);
}
//验证path
boolean
check
=
miaoshaService
.
checkPath
(
user
,
goodsId
,
path
);
if
(!
check
){
return
Result
.
error
(
CodeMsg
.
REQUEST_ILLEGAL
);
}
// //使用RateLimiter 限流
// RateLimiter rateLimiter = RateLimiter.create(10);
// //判断能否在1秒内得到令牌,如果不能则立即返回false,不会阻塞程序
// if (!rateLimiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
// System.out.println("短期无法获取令牌,真不幸,排队也瞎排");
// return Result.error(CodeMsg.MIAOSHA_FAIL);
//
// }
//是否已经秒杀到
MiaoshaOrder
order
=
orderService
.
getMiaoshaOrderByUserIdGoodsId
(
user
.
getId
(),
goodsId
);
if
(
order
!=
null
){
...
...
src/main/java/com/geekq/miaosha/controller/RateLimiterController.java
0 → 100644
浏览文件 @
9c73ca56
package
com.geekq.miaosha.controller
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.RequestMapping
;
@Controller
@RequestMapping
(
"/ratelimiter"
)
public
class
RateLimiterController
{
}
target/classes/com/geekq/miaosha/DemoTask$1.class
0 → 100644
浏览文件 @
9c73ca56
文件已添加
target/classes/com/geekq/miaosha/DemoTask$2.class
0 → 100644
浏览文件 @
9c73ca56
文件已添加
target/classes/com/geekq/miaosha/DemoTask.class
0 → 100644
浏览文件 @
9c73ca56
文件已添加
target/classes/com/geekq/miaosha/Test.class
0 → 100644
浏览文件 @
9c73ca56
文件已添加
target/classes/com/geekq/miaosha/config/UserArgumentResolver.class
浏览文件 @
9c73ca56
无法预览此类型文件
target/classes/com/geekq/miaosha/controller/MiaoshaController.class
浏览文件 @
9c73ca56
无法预览此类型文件
target/classes/com/geekq/miaosha/controller/RateLimiterController.class
0 → 100644
浏览文件 @
9c73ca56
文件已添加
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录