- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java并发编程之线程之间的共享和协作由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
用处 。
对象锁和类锁 。
spring会从数据库连接池中获得一个connection,然会把connection放进threadlocal中,也就和线程绑定了,事务需要提交或者回滚,只要从threadlocal中拿到connection进行操作.
1
2
3
4
5
6
7
8
9
10
11
12
|
以jdbc为例,正常的事务代码可能如下:
dbc =
new
databaseconnection();
//第1行
connection con = dbc.getconnection();
//第2行
con.setautocommit(
false
);
// //第3行
con.executeupdate(...);
//第4行
con.executeupdate(...);
//第5行
con.executeupdate(...);
//第6行
con.commit();第
7
行
上述代码,可以分成三个部分:
事务准备阶段:第
1
~
3
行
业务处理阶段:第
4
~
6
行
事务提交阶段:第
7
行
|
1
2
3
4
5
6
7
8
|
connection conn = getconnection();
dao1 dao1 =
new
dao1(conn);
dao1.exec();
dao2 dao2 =
new
dao2(conn);
dao2.exec();
dao3 dao3 =
new
dao3(conn);
dao3.exec();
conn.commit();
|
void set(object value) 。
public object get() 。
public void remove() 。
protected object initialvalue() 。
public final static threadlocal resource = new threadlocal() 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
public
class
threadlocal<t> {
//get方法,其实就是拿到每个线程独有的threadlocalmap
//然后再用threadlocal的当前实例,拿到map中的相应的entry,然后就可以拿到相应的值返回出去。
//如果map为空,还会先进行map的创建,初始化等工作。
public
t get() {
//先取到当前线程,然后调用getmap方法获取对应线程的threadlocalmap
thread t = thread.currentthread();
threadlocalmap map = getmap(t);
if
(map !=
null
) {
threadlocalmap.entry e = map.getentry(
this
);
if
(e !=
null
) {
@suppresswarnings
(
"unchecked"
)
t result = (t)e.value;
return
result;
}
}
return
setinitialvalue();
}
// thread类中有一个 threadlocalmap 类型成员,所以getmap是直接返回thread的成员
threadlocalmap getmap(thread t) {
return
t.threadlocals;
}
// threadlocalmap是threadlocal的静态内部类
static
class
threadlocalmap {
threadlocalmap(threadlocal<?> firstkey, object firstvalue) {
// 用数组保存 entry , 因为可能有多个变量需要线程隔离访问,即声明多个 threadlocal 变量
table =
new
entry[initial_capacity];
int
i = firstkey.threadlocalhashcode & (initial_capacity -
1
);
// entry 类似于 map 的 key-value 结构
// key 就是 threadlocal, value 就是需要隔离访问的变量
table[i] =
new
entry(firstkey, firstvalue);
size =
1
;
setthreshold(initial_capacity);
}
...
}
//entry内部静态类,它继承了weakreference,
//总之它记录了两个信息,一个是threadlocal<?>类型,一个是object类型的值
static
class
entry
extends
weakreference<threadlocal<?>> {
/** the value associated with this threadlocal. */
object value;
entry(threadlocal<?> k, object v) {
super
(k);
value = v;
}
}
//getentry方法则是获取某个threadlocal对应的值
private
entry getentry(threadlocal<?> key) {
int
i = key.threadlocalhashcode & (table.length -
1
);
entry e = table[i];
if
(e !=
null
&& e.get() == key)
return
e;
else
return
getentryaftermiss(key, i, e);
}
//set方法就是更新或赋值相应的threadlocal对应的值
private
void
set(threadlocal<?> key, object value) {
...
}
...
}
public
class
thread
implements
runnable {
/* threadlocal values pertaining to this thread. this map is maintained
* by the threadlocal class. */
threadlocal.threadlocalmap threadlocals =
null
;
...
}
|
将堆内存大小设置为-xmx256m 。
启用一个线程池,大小固定为5个线程 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
//5m大小的数组
private
static
class
localvariable {
private
byte
[] value =
new
byte
[
1024
*
1024
*
5
];
}
// 创建线程池,固定为5个线程
private
static
threadpoolexecutor poolexecutor
=
new
threadpoolexecutor(
5
,
5
,
1
, timeunit.minutes,
new
linkedblockingqueue<>());
//threadlocal共享变量
private
threadlocal<localvariable> data;
@override
public
void
run() {
//场景1:不执行任何有意义的代码,当所有的任务提交执行完成后,查看内存占用情况,占用 25m 左右
//system.out.println("hello threadlocal...");
//场景2:创建 数据对象,执行完成后,查看内存占用情况,与场景1相同
//new localvariable();
//场景3:启用 threadlocal,执行完成后,查看内存占用情况,占用 100m 左右
threadlocaloom obj =
new
threadlocaloom();
obj.data =
new
threadlocal<>();
obj.data.set(
new
localvariable());
system.out.println(
"update threadlocal data value.........."
);
//场景4: 加入 remove(),执行完成后,查看内存占用情况,与场景1相同
//obj.data.remove();
//分析:在场景3中,当启用了threadlocal以后确实发生了内存泄漏
}
|
场景1:
场景2:
场景3:
场景4:
场景分析:
场景3分析:
从表面上看内存泄漏的根源在于使用了弱引用。为什么使用弱引用而不是强引用?下面我们分两种情况讨论:
因此,threadlocal内存泄漏的根源是:
总结:
错误使用threadlocal导致线程不安全:
存在如下问题:
是指一个线程a调用了对象o的wait()方法进入等待状态,而另一个线程b调用了对象o的notify()或者notifyall()方法,线程a收到通知后从对象o的wait()方法返回,进而执行后续操作.
上述两个线程通过对象o来完成交互,而对象上的wait()和notify/notifyall()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作.
notify():
通知一个在对象上等待的线程,使其从wait方法返回,而返回的前提是该线程获取到了对象的锁,没有获得锁的线程重新进入waiting状态.
notifyall():
通知所有等待在该对象上的线程.
wait():
调用该方法的线程进入 waiting状态,只有等待另外线程的通知或被中断才会返回.需要注意,调用wait()方法后,会释放对象的锁.
wait(long):
超时等待一段时间,这里的参数时间是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回; 。
wait (long,int):
对于超时时间更细粒度的控制,可以达到纳秒; 。
等待方遵循如下原则:
1
2
3
4
5
6
|
synchronized
(对象){
while
(条件不满足){
对象.wait();
}
对应的逻辑
}
|
通知方遵循如下原则:
1
2
3
4
|
synchronized
(对象){
改变条件
对象.notifyall();
}
|
在调用wait()、notify()系列方法之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait() 方法、notify()系列方法; 。
notify() 和 notifyall() 应该用谁?
调用场景:
调用yield() 、sleep()、wait()、notify()等方法对锁有何影响?
到此这篇关于java并发编程之线程之间的共享和协作的文章就介绍到这了,更多相关java线程之间的共享和协作内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/chentian114/article/details/115689035 。
最后此篇关于Java并发编程之线程之间的共享和协作的文章就讲到这里了,如果你想了解更多关于Java并发编程之线程之间的共享和协作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试在多线程环境中实现某种累积逻辑;我想知道没有 lock 和 synchronized 关键字是否有更好/更快的方法来做到这一点?以下是我当前的代码: public class Concurr
我需要帮助构建一个实现信号量的监视器,简单的 C 示例就可以。 这是为了证明可以在任何可以使用信号量的地方使用监视器。 最佳答案 如果您说允许使用互斥锁/condvars,请检查: #include
我已经构建了一些返回部分产品目录的 ajax,并且我正在尝试将 xml 输出到文档中,到目前为止,这是我所拥有的: $("#catalog").append("Item NamePriceDe
很抱歉,如果我的问题之前已经被问过,或者它太明显了,但我真的需要澄清这一点。感谢您的帮助。 在多用户界面中,如果来自不同用户的相同事务同时到达服务器,会发生什么? 我有下一张表: create tab
这可能是一个愚蠢的问题,但是这个程序的输出(它的方式)可以为零吗? public class Test2{ int a = 0; AtomicInteger b = new Atomi
假设我本地主机上的一个网站处理每个请求大约需要 3 秒。这很好,正如预期的那样(因为它在幕后进行了一些奇特的网络)。 但是,如果我在选项卡(在 firefox 中)中打开相同的 url,然后同时重新加
我对 MongoDB 的读锁定有点困惑。单个集合可以支持多少个并发读取操作? 最佳答案 如 tk 给出的链接中所写:http://www.mongodb.org/pages/viewpage.acti
如果有四个并发的 CUDA 应用程序在一个 GPU 中竞争资源会发生什么这样他们就可以将工作卸载到图形卡上了? Cuda Programming Guide 3.1 提到那里 某些方法是异步的: 内核
👊上次的百度面试遇到了关于spark的并发数的问题,今天我们就来将这些问题都一并解决一下,图画的的有点丑,还行大家见谅,百度实习的问题我放在了下面的链接👇: 链接: 2022百度大数据开发工程师实
我对 Groovy 线程有疑问。 我的任务是以某种方式翻译给定目录中的每个文件 并将生成的输出放在其他目录中的文件中。 我编写了以下代码,该代码有效: static def translateDir(
Java中的同步和锁定有什么区别? 最佳答案 synchronized是语言关键字;锁是对象。 当一个方法或代码块被标记为同步时,您是说该方法或代码块必须先获得某个锁对象(可以在同步的语法中指定)才能
我需要创建一个能够同时处理来自客户端的多个请求的并发 RPC 服务器。 使用 rpcgen linux编译器(基于sun RPC),不支持-A为并发服务器创建 stub 的选项。 (-A 选项在 so
System.out.println("Enter the number of what you would like to do"); System.out.println("1 = Manuall
我正在将我的应用程序移植到 iOS 8.0 并注意到 UIAlertView 已被弃用。 所以我改变了使用 UIAlertController 的方法。这在大多数情况下都有效。 除了,当我的应用程序打
我正在逐行同时读取两个文本文件。 我特别想做的是当lineCount在每个线程上都是相同的我想看看扫描仪当前正在读取的字符串。 我环顾四周寻找可以实现的某些模式,例如 Compare and Swap
我正在阅读 Java Concurrency in Practice .在章节中断政策部分 取消和关闭 它提到 A task should not assume anything about the
我正在尝试学习线程,互斥等的基础知识。遵循here的文档和示例。在下面的代码中,我得到预期的输出。问题: 想确认我是否有任何陷阱?我们如何改善下面的代码? 我的线程在哪一行尝试获取互斥锁或正在等待互斥
并发是指两个任务在不同的线程上并行运行。但是,异步方法并行运行,但在同一个线程上。这是如何实现的?另外,并行性怎么样? 这三个概念有什么区别? 最佳答案 并发和并行实际上与您正确推测的原理相同,两者都
以此ConcurrentDouble类定义为例: public class ConcurrentDouble { public double num = 0; public void subt
在得知并发确实增加了许多人的吞吐量后,我一直计划在项目中使用并发。现在我在多线程或并发方面还没有做太多工作,因此决定在实际项目中使用它之前学习并进行简单的概念验证。 以下是我尝试过的两个示例: 1.
我是一名优秀的程序员,十分优秀!