当前位置:萝卜系统 > 硬件软件教程 > 详细页面

JAVA并发编程阶段,处理死锁问题与线程局部原理区分的概述

JAVA并发编程阶段,处理死锁问题与线程局部原理区分的概述

更新时间:2023-06-21 文章作者:未知 信息来源:网络 阅读次数:

根据运行的环境,操作系统可以分为桌面操作系统,手机操作系统,服务器操作系统,嵌入式操作系统等。

避免线程死锁_java线程死锁怎么解决_java多线程避免死锁

让我们首先看一下死锁的概念: 一组相互竞争的线程正在互相等待,并导致“永久”阻塞. 我们称这为僵局. 如果存在死锁,则必须有一个活锁. 是活锁吗?也就是说,任务和执行程序都不会被阻塞. 由于不满足某些条件,因此重试->尝试执行->执行失败的过程称为活动锁.

只要满足以下四个条件,就不可避免地会发生死锁:

根据上述四个死锁条件,只需破坏其中一个条件,就不会发生死锁.

其作用是使线程的执行结果对后续线程的访问可见.

ThreadLocal实际上是一种线程隔离机制,用于确保在多线程环境中访问共享变量的安全性.

 /**
* Sets the current thread's copy of this thread-local variable
* to the specified value.  Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
*        this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
 

当地图不为空时,执行map.set(this,value)方法,代码如下:

private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
//根据哈希码和数组长度求得元素的放置位置,即Entry数组的下标
int i = key.threadLocalHashCode & (len-1);
//从i开始遍历到数组的最后一个Entry(进行线性探索)
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
//如果key相等,就覆盖value
if (k == key) {
e.value = value;
return;
}
//如果key为空,用新的key,value,同时清理历史key=null(弱引用)的旧数据
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
//如果超过设置的閥值,则需要进行扩容
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
 

上面的源代码中使用了线性检测方法来解决哈希冲突问题.

java线程死锁怎么解决_避免线程死锁_java多线程避免死锁

那么什么是线性检测?

线性检测是一种开放式寻址策略. 哈希表通过密钥直接访问数据结构,并且密钥通过哈希函数映射到哈希表中某个位置的访问记录,从而加快了搜索速度. 该存储记录称为哈希表(也称为哈希表).

有两种方法可以解决此冲突:

一个流行的解释是: 当我们下蹲并发现坑被占用时,我们会寻找下一个坑. 如果后面的坑是空的,那么它将被占用;如果后一个坑被占用,则继续遍历后坑直到找到可用的坑为止,否则您将一直保持holding陷.

private void replaceStaleEntry(ThreadLocal<?> key, Object value,
int staleSlot) {
Entry[] tab = table;
int len = tab.length;
Entry e;
// Back up to check for prior stale entry in current run.
// We clean out whole runs at a time to avoid continual
// incremental rehashing due to garbage collector freeing
// up refs in bunches (i.e., whenever the collector runs).
//向前扫描,查找最前一个无效的slot
int slotToExpunge = staleSlot;
for (int i = prevIndex(staleSlot, len);
(e = tab[i]) != null;
i = prevIndex(i, len))
if (e.get() == null)
//通过循环遍历,可以定位到最前面的一个无效的slot
slotToExpunge = i;
// Find either the key or trailing null slot of run, whichever
// occurs first
//从i开始遍历到数组的最后一个Entry(进行线性探索)
for (int i = nextIndex(staleSlot, len);
(e = tab[i]) != null;
i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
// If we find key, then we need to swap it
// with the stale entry to maintain hash table order.
// The newly stale slot, or any other stale slot
// encountered above it, can then be sent to expungeStaleEntry
// to remove or rehash all of the other entries in run.
//找到匹配的key
if (k == key) {
//更新对应的slot对应的value
e.value = value;
//与无效的slot进行替换
tab[i] = tab[staleSlot];
tab[staleSlot] = e;
// Start expunge at preceding stale entry if it exists
////如果最早的一个无效的slot和当前的staleSlot相等,则从i作为清理的起点
if (slotToExpunge == staleSlot)
slotToExpunge = i;
//从slotToExpunge开始做一次连续的清理
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
// If we didn't find stale entry on backward scan, the
// first stale entry seen while scanning for key is the
// first still present in the run.
//如果当前的slot已经无效,并且向前扫描过程中没有无效slot,则更新slotToExpunge为当前位置
if (k == null && slotToExpunge == staleSlot)
slotToExpunge = i;
}
// If key not found, put new entry in stale slot
//如果key对应的value在entry中不存在,则直接放一个新的entry
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);
// If there are any other stale entries in run, expunge them
//如果有任何一个无效的slot,则做一次清理
if (slotToExpunge != staleSlot)
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}
 

ThreadLocal的源代码如下:

//HASH_INCREMENT是为了让哈希码能均匀的分布在2的N次方的数组里
private static final int HASH_INCREMENT = 0x61c88647;
/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
 

它定义了一个魔术值HASH_INCREMENT = 0x61c88647. 对于实例变量threadLocalHashCode,无论何时创建ThreadLocal实例,此值都将为getAndAdd(0x61c88647).

HASH_INCREMENT在某种算法的帮助下,哈希码可以以2的幂次均匀地分布到N次方,这确保了哈希表的分散性并降低了冲突的可能性. 让我们编写一些测试代码:

public class FibonacciHash {
private static final int HASH_INCREMENT = 0x61c88647;
public static void main(String[] args) {
magicHash(16);
magicHash(32);
}
private static void magicHash(int size) {
int hashCode = 0;
for (int i = 0; i < size; i++) {
hashCode = i * HASH_INCREMENT + HASH_INCREMENT;
System.out.print((hashCode & (size - 1)) + " ");
}
System.out.println("");
}
}
 

执行main()方法的结果:

避免线程死锁_java线程死锁怎么解决_java多线程避免死锁

7 14 5 12 3 10 1 8 15 6 13 4 11 2 9 0
7 14 21 28 3 10 17 24 31 6 13 20 27 2 9 16 23 30 5 12 19 26 1 8 15 22 29 4 11 18 25 0
 

生成的哈希码的分布确实非常均匀,并且没有冲突.

前端架构设计: 模型驱动的前端开发JAVA并发编程的渐进文章,探讨线程安全volatile关键字如何确保可见性数据链接层eBPF技术的高性能ACL浏览器架构,单线程js,事件循环,消息队列,宏任务和微任务

Web前端技术交流网络:

我想创建一个函数,如果一个单词中的所有字母都按字母顺序出现,则返回true.

但是通话后java多线程避免死锁,它一直向我返回True,我希望其他人看看出了什么问题

”`

def abcd():

a =“ abcdc”

fo ...

Ajax请求中的get和post有什么区别? Ajax request中的get和post有什么区别? Ajax request中的get和post有什么区别? Ajax request中的get和post有什么区别?请求Ajax时获取并获取...

java线程死锁怎么解决_避免线程死锁_java多线程避免死锁

#我下载了vue-element-admin,并在本地npm insatall之后的npm run dev之后报告了一个错误. 删除node_modules后,无法进行重置.

C: UsersLe’novoDesktopproj ...

我最近学习了Java语言. 我是新手. 我想使用TCP套接字进行网络编程,以使服务器接受来自客户端的文件,但是遇到错误. 有人知道如何解决吗?

”`

//这是服务器端代码

公共课...

JS中“ ==”和“ ===”之间的区别JS中“ ==”和“ ===”之间的区别JS中“ ==”和“ ===”之间的区别“ = =“和” ===“之间的区别JS中” ==“和” ===“之间的区别JS中” ==“和” ===“之间的区别

在紧急购买功能中,为了防止产品超卖,如果使用redis锁,则会引入一个锁. 这里的问题是它是否是...继续阅读关于同时购买获得锁的问题

给出以下代码,如果__name__ ==“ __main__”怎么办?

#线程示例

导入时间,线程

java多线程避免死锁_避免线程死锁_java线程死锁怎么解决

def myfunction(字符串,睡眠时间,锁定java多线程避免死锁,* args):

为True时:

lock.acquire()

...

...请参阅有关302303的文章...继续阅读有关HTTP响应代码302303307的两个问题

**我在Github上提取了一组标准Vue模板以进行本地开发,并且工作正常. 也就是说,Chrome浏览器的“源”模块无法准确定位源代码. 如果找不到,则无法对其进行调试.

**

![图片描述](...

以前,使用全局变量在不同路径之间共享参数. 我想问一下打开多线程后该怎么办? @ app.r ...继续阅读flask使用多个线程后,每个线程中的不同路由如何共享参数?

在Mac上使用Command + Shift + B快捷键构建.net核心解决方案时,报告了错误: bin / bash: dotnet: 找不到命令te

![图片描述]()![图片描述](…


本文来自本站,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-284711-1.html



温馨提示:喜欢本站的话,请收藏一下本站!

本类教程下载

系统下载排行

网站地图xml | 网站地图html