ThreadLoacl、InheritableThreadLocal学习

多模态预训练物理:知识流、协同与训练配方 多模态预训练是AI领域的热点,但实践中常遇到模态退化、训练不稳定等问题。理解其内在机制比堆叠技巧更重要。本文从知识流、模态协同、早期统一与训练配方四个维度,解析多模态预训练的工作物理原理。知识流描述了信息在模态间的传递路径,模态协同解释了何时产生1+1>2的效果,早期统一讨论了架构设计中的融合时机,训练配方则提供了可复现的工程配置。这套框架帮助研究者在实际项目中定位问题、设计实验,并提升下游任务性能。适用于训练或微调多模态模型的技术人员。 阅读详情

如果写过多线程的代码,你肯定考虑过线程安全问题,更进一步你可能还考虑在在线程安全的前提下性能的问题。大多数情况下大家用来解决线程安全问题都会使用同步,比如用synchron或者concurrent包提供的各种锁,当然这些都能解决问题。但有多线程做同步一定会涉及到资源争抢和等待的问题。java中各种同步方法都是提供一种准入机制,JVM会调用系统同步原语来保证临界区任意时刻只能有一个线程进入,那必然其他线程都得等待了,性能的瓶颈就在这同步上了。
  解决问题最好的方式是啥?当然是避免问题的发生了。ThreadLocal就是用这样一种方式提升性能的。ThreadLocal也不是万金油,它也只能在多线程之间数据相互独立的情况下使用,如果是多线程间的数据同步,还得使用某个同步的方式。

要理解ThreadLocal的工作原理,还需要了解Thread,ThreadLocalMap

每一个ThreadLocal只能存储一个值,一个ThreadLocal可以被多个线程记录,一个线程Thread也可以记录多个ThreadLocal,他们通过ThreadLocalMap来关联。


ThreadLocal

1. 先从ThreadLocal提供的几个公共方法入口来分析它的使用原理

get方法

    public T get() {
        Thread t = Thread.currentThread();
        // 获取当前线程对象保存的ThreadLocalMap,存储在线程对象的成员变量threadLocals中
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            // 关于ThreadLocalMap的相关操作,另外写在其他地方
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        // 如果当前线程对象的threadLocals尚未创建,则设置初始值
        return setInitialValue();
    }

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    private T setInitialValue() {
        // 获取默认的初始值,如未重写该方法,默认为null
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }


    /**
     * initialValue方法,默认返回null,如果希望在未进行set操作之前,调用get方法时能返回一个非
     * null初始值,那么必须创建一个ThreadLocal的子类对象并重写该方法。
     */
    protected T initialValue() {
        return null;
    }

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

set方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        // 可以发现,实际的赋值是对当前线程绑定的ThreadLocalMap进行赋值
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

remove方法

     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

可以发现,get,set ,remove方法中的逻辑都十分简单,但都涉及到了许多对ThreadLocalMap的操作,实际上,我认为ThreadLoacl的核心就是ThreadLocalMap,ThreadLoacl为每个线程存储的值实际上就是通过 对每个线程对象中的ThreadLocalMap 进行赋值,所以即使在多线程环境下,我们对同一个ThreadLoacl对象进行set,get操作,实际上操作的是每个线程下不同的ThreadLocalMap对象,所以不存在线程安全问题。所以我们重点关注一下ThreadLocalMap 。


Thread

每一个线程对象中都要一个ThreadLocalMap成员变量,初始值为null,其初始化由ThreadLocal完成

// 这个map通过ThreadLocal类,保留了与此线程相关的ThreadLocal值。
ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap 简单介绍

ThreadLocalMap 是 ThreadLocal  的一个静态成员内部类,且访问权限为默认,并且没有提供任何公有方法,这就意味着除了在ThreadLocal中,其他地方是无法对其进行操作的。另外,它没有实现Map接口,emmm 这就意味它不是一个标准的map了

核心成员  private Entry[] table;

这个Entry是ThreadLocalMap的一个静态内部类,可以简单理解为一个键值对,键始终为ThreadLocal实例对象,值为该ThreadLocal对象存储的值。该类继承了WeakReference(不了解),当key为null时,意味着该key已经无效,意味着这个entry已经可以从table这个数组中移除。

通过继承至父类的get()方法,可以获取key

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

构造方法

需要提出来的是,每个Entry在table数组中的位置的计算方式比较特殊(具体方式看代码),用这种方式,不同的key可能会得出相同的下标i,如何解决这种冲突,参考博文https://blog.youkuaiyun.com/xindoo/article/details/88777833#commentBox

        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            // 构造一个初始容量的Entry数组
            table = new Entry[INITIAL_CAPACITY];
            // 计算出每个元素在数组中的位置
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            // 数组扩容相关,比较常见,不关心
            setThreshold(INITIAL_CAPACITY);
        }

set方法

        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;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

从set方法中我们就可以看出ThreadLocalMap和HashMap,TreeMap的设计不同之处。首先也是对Key求hash值做定位,但当遇到hash冲突的时候,它的选择不是开链,而是调用nextIndex往后移动,直到遇见某个entry为null或者其key和要插入的key一样。同时,插入的过程也会调用replaceStaleEntry对Map做清理,清理过程比较复杂,稍后介绍。插入后,如果size大于阀值,也会对整个map做扩容操作。

remove方法

        private void remove(ThreadLocal<?> key) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                if (e.get() == key) {
                    e.clear();
                    expungeStaleEntry(i);
                    return;
                }
            }
        }

get方法

        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);
        }

        private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;

            while (e != null) {
                ThreadLocal<?> k = e.get();
                if (k == key)
                    return e;
                // 说明对应entry不存在
                if (k == null)
                    // 如果键为null,说明这个entry已经无效了,该方法用于删除那些无用的entry,不关心具体实现
                    expungeStaleEntry(i);
                else
                    // 这里说明发生了下标冲突,k != key两个不同的键产生了相同的下标
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }

因为刚刚说到ThreadLocalMap处理key冲突的方式是往后移,直到有空闲的位置。这样虽然实现简单,但查的时候问题就来了,首先根据参数key的hash值算出目标entry的位置

1. 如果目标位置entry为null,意味着不存在该键key对应的entry

2. 如果目标位置entry存在,但其键k与作为参数的key不等,这就意味着发生了下标冲突,插入过程中,位置被后移,或者确实从未插入,不存在该键key对应的entry

所以得往后遍历,直到找到或者遍历到某个空Entry。如果你仔细想想可能就会发现问题,如果只是遍历到遇到null,而不是遍历整个tab,可能会漏掉。比如下面这个例子。

  | 0 | 1 | 2 | 3 | 5 | 6 | 7 |  
  |   | a | b | c | d | e |   |     

开始的时候,tab状态是这样的,现在我要插入一个h,其hashcode恰好是1,然而a已经在那了,按插入逻辑,h只能插到7的位置了,插入后如下。

  | 0 | 1 | 2 | 3 | 5 | 6 | 7 |  
  |   | a | b | c | d | e | h |     

后来,我把c删掉,变成了下面这样。如果我现在想查h,按照上面getEntry的逻辑,是不是遍历到3就停了,所以找不到h了? getEntry的逻辑表面确实是这样,但实际上getEntryAfterMiss、remove、get时都会直接或者间接调用expungeStaleEntry会对表里的数据做整理。expungeStaleEntry()除了利用弱引用的特性对tab中Entry做清理外,还会对之前Hash冲突导致后移的Entry重新安放位置。所以不可能出现下面这种tab排放的。

  | 0 | 1 | 2 | 3 | 5 | 6 | 7 |  
  |   | a | b |   | d | e | h |     
        private int expungeStaleEntry(int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;

            // expunge entry at staleSlot
            tab[staleSlot].value = null;
            tab[staleSlot] = null;
            size--;

            // Rehash until we encounter null
            Entry e;
            int i;
            for (i = nextIndex(staleSlot, len);
                 (e = tab[i]) != null;
                 i = nextIndex(i, len)) {
                ThreadLocal<?> k = e.get();
                if (k == null) {
                    e.value = null;
                    tab[i] = null;
                    size--;
                } else {
                    int h = k.threadLocalHashCode & (len - 1);
                    if (h != i) {
                        tab[i] = null;

                        // Unlike Knuth 6.4 Algorithm R, we must scan until
                        // null because multiple entries could have been stale.
                        while (tab[h] != null)
                            h = nextIndex(h, len);
                        tab[h] = e;
                    }
                }
            }
            return i;
        }

还有set中调用的replaceStaleEntry(),代码很长,其实也是保证key失效的Entry被清理,Hash冲突的key能放回正确的位置。

        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).
            int slotToExpunge = staleSlot;
            for (int i = prevIndex(staleSlot, len);
                 (e = tab[i]) != null;
                 i = prevIndex(i, len))
                if (e.get() == null)
                    slotToExpunge = i;

            // Find either the key or trailing null slot of run, whichever
            // occurs first
            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.
                if (k == key) {
                    e.value = value;

                    tab[i] = tab[staleSlot];
                    tab[staleSlot] = e;

                    // Start expunge at preceding stale entry if it exists
                    if (slotToExpunge == staleSlot)
                        slotToExpunge = i;
                    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.
                if (k == null && slotToExpunge == staleSlot)
                    slotToExpunge = i;
            }

            // If key not found, put new entry in stale slot
            tab[staleSlot].value = null;
            tab[staleSlot] = new Entry(key, value);

            // If there are any other stale entries in run, expunge them
            if (slotToExpunge != staleSlot)
                cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
        }

看这么多复杂的代码,最后看个简单的resize(),ThreadLocalMap的resize相较于HashMap的简单多了,就是新建一个长度为当前2倍的tab,然后把当前tab中的每个entry重新计算index再插入新tab。

        private void resize() {
            Entry[] oldTab = table;
            int oldLen = oldTab.length;
            int newLen = oldLen * 2;
            Entry[] newTab = new Entry[newLen];
            int count = 0;

            for (Entry e : oldTab) {
                if (e != null) {
                    ThreadLocal<?> k = e.get();
                    if (k == null) {
                        e.value = null; // Help the GC
                    } else {
                        int h = k.threadLocalHashCode & (newLen - 1);
                        while (newTab[h] != null)
                            h = nextIndex(h, newLen);
                        newTab[h] = e;
                        count++;
                    }
                }
            }

            setThreshold(newLen);
            size = count;
            table = newTab;
        }

使用场景

  1. 数据库连接
  2. Cache
  3. 线程池

参考资料

  1. ThreadLocal源码
  2. 简单理解ThreadLocal原理和适用场景,多数据源下ThreadLocal的应用

测试代码

package threadLocal;

/**
 * @author LiFeng
 * @create 2019-11-05 上午 11:08
 * @describe
 */
public class TestLocal {
	public static void main(String[] args) {
		ThreadLocal<String> t = new ThreadLocal();
		String s = t.get();
		System.out.println(s);

		// 重写initialValue的方法,未set直接调用get也能获得一个初始值
		ThreadLocal<String> t2 = new ThreadLocal<String>() {
			@Override
			protected String initialValue() {
				return "lifeng";
			}
		};

		s = t2.get();
		System.out.println(s);

		t2.remove();
		s = t2.get();
		System.out.println(s);

		t2.set("hello world");
		s = t2.get();
		System.out.println(s);

		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("thread1:" + t.get());
				System.out.println("thread1:" + t2.get());
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});

		thread.start();
		System.out.println("wait...");
	}

}

测试结果如图

因为无法在外部获取thread对象中的ThreadLocalMap,所以我通过debug的方式观察了一下。符合预期


 InheritableThreadLocal

InheritableThreadLocal 继承自 ThreadLocal,但是仅仅是重写了3个方法,可以看到并没有什么复杂的操作。它的特性是,子线程可以继承父线程的初始值,那么它是如何实现的呢? 对于后两个方法非常简单,用处也在上文提到过。稍后介绍childValue方法的用途。

其实,这个要联系到Thread类的核心构造方法,这个我在另一篇博文中详细介绍过,这里简单说一下。

对于这个参数,默认为true,仅有一个构造方法可以设定其值为false,

我们平常创建线程时,绝大多数时候是不会调用此方法的,所以inheritThreadLocals这个参数通常为true,它的作用是

简单说,就是利用父线程中的ThreadLocal.ThreadLocalMap inheritableThreadLocals属性来构建自己的inheritableThreadLocals

可以认为这是一次copy操作。这种构建是一次性的,之后父线程修改其inheritableThreadLocals中的值,子线程并不受其影响。

这里我们也看到了childValue方法的调用,在ThreadLocal方法中未被重写时,它是这样的,这是一种典型的模板方法模式,定义

了构造ThreadLocalMap的步骤,但将其中某个步骤交由其子类去具体实现。

对于childValue方法,我们也可以进一步重写,以达到值继承并进行修改的效果。写了一个简单的demo如下。

测试代码:

package threadLocal;

/**
 * @author LiFeng
 * @create 2019-11-06 上午 10:35
 * @describe
 */
public class TestInheritable {

	public static void main(String[] args) {
		InheritableThreadLocal<String> iht = new InheritableThreadLocal<>();
		iht.set("first value");
		System.out.println("main get: " + iht.get());

		InheritableThreadLocal<String> iht2 = new InheritableThreadLocal<String>() {
			@Override
			protected String childValue(String parentValue) {
				return parentValue + "取得父线程中的值并加以补充修改";
			}
		};
		iht2.set("iht2");
		System.out.println("main get: " + iht2.get());

		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("thread-01 get: " + iht.get());
				System.out.println("thread-01 get: " + iht2.get());
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("thread-01 get: " + iht.get());
			}
		}, "thread-01").start();


		// 模拟在main线程中将iht中的值进行修改,发现在thread-01线程中并不会受影响
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		iht.set("second value");
		System.out.println("main get: " + iht.get());


	}

}

 

 

Grok 3国内怎么用?超详细使用指南+实用指令模板 主要是用于快速分析学术论文,提取关键信息,总结研究成果。Analyze the following research paper: [粘贴或上传论文内容]1. Extract key findings, methodologies, and conclusions. (提取主要发现、方法和结论。2. Identify statistical significance and data points. (识别统计显著性和数据点。 阅读详情

相关推荐

配置oem 13c以监控管理数据库

使用oem13c监控数据库

雅冰石的专栏 1812

Java 多线程为啥要有ThreadLocal,怎么用,这篇讲全了!

前面我们学习的线程并发时的同步控制,是为了保证多个线程对共享数据争用时的正确性的。那如果一个操作本身不涉及对共享数据的使用,相反,只是希望变量只能由创建它的线程使用(即线程隔离)就需要到线程本地存储了。Java 通过 提供了程序对线程本地存储的使用。通过创建 类的实例,让我们能够创建只能由同一线程读取和写入的变量。因此,即使两个线程正在执行相同的代码,并且代码引用了相同名称的 变量,这两个线程也无法看到彼此的存储在 里的值。否则也就不能叫线程本地存储了。本文大纲如下: 是 Java 内置的类,全称

BASK2311的博客 980

C#与AutoCAD插件开发实战:从零构建你的第一个自定义命令

本文为AutoCAD插件开发新手提供了一份完整的C#实战指南。从搭建Visual Studio开发环境、添加AutoCAD .NET API引用,到编写并注册第一个“Hello AutoCAD”自定义命令,再到实现一个交互式绘制十字线的实用命令,详细讲解了核心代码结构与调试技巧。文章旨在帮助工程师和设计师利用C#自动化重复绘图任务,显著提升工作效率。

weixin_29294597的博客 435

【线程】InheritableThreadLocal 剖析 (十六)

1. InheritableThreadLocal 能干嘛 2. InheritableThreadLocal 有什么坑?

Sword52888的博客 708

飞书云文档API操作详细介绍

开通云文档API、python程序调用飞书api、飞书获取app_id和app_secret、

Brother_ning的博客 1万+

传感器模块的电路艺术:从引脚定义到系统集成的设计哲学

本文深入探讨传感器模块的电路设计艺术,从引脚定义到系统集成的完整设计哲学。重点解析电源管理、信号处理及I2C通信协议等核心电路原理,分享多模块协同中的电源架构、信号完整性和接地策略,为硬件工程师提供实用的系统级设计思维与实战案例。

o1p2q3r的博客 228

InheritableThreadLocal 使用的问题及解决办法

问题背景 最近公司负责的项目总是出现莫名其妙的串号的问题,具体表现是一次请求里日志却记录的多个userId(一次请都只会有一个userId),看了很久的报文,分析了很久的代码,终于有了点眉目。 问题分析 这类问题主要出现在一个主任务启动的多个线程并发执行造成的,执行分析使用的是 InheritableThreadLocal private static class InheritableThreadLocalContext extends InheritableThreadLocal<ThreadLo

3027

【yolov8】与yolov5的区别及改进详解

yolov8-----有点厉害的目标检测框架.

qq_44878985的博客 3万+

ThreadLoacl,InheritableThreadLocal,原理,以及配合线程池使用的一些坑

虽然使用AOP可以获取方法签名,但是如果要获取方法中计算得出的数据,那么就得使用ThreadLocal,如果还涉及父线程,那么可以选择InheritableThreadLocal. 注意:理解一些原理能够减少很多不可控问题,最简单的使用方式就是不要交给线程池处理.为了提高一点性能,而导致数据错误得不偿失. 2018年4月12日 12:44:41更新 关于InheritableThreadLoc...

hellozhxy的博客 540

GEO芯片数据下载和探针ID转换(保姆级教程)

R语言安装、GEO芯片数据下载、探针ID转换

qq_43138237的博客 3万+

OpenWRT二级路由DHCP客户端配置:实现IPv4 WAN自动获取与网段隔离

本文详细讲解了如何将OpenWRT配置为二级路由器,重点在于设置其WAN口为DHCP客户端以自动获取IPv4地址,并修改LAN口网段实现与上级网络的隔离。文章提供了从网络拓扑规划、具体配置步骤到防火墙设置的完整指南,并分享了常见问题排查与避坑经验,帮助用户构建稳定且功能独立的家庭网络环境。

weixin_29268267的博客 295

Java多线程之局部变量ThreadLoacl,InheritableThreadLocal

当我们想把线程和某些变量联系起来的时候,有人就会说,那不简单,我在run()里面定义一个不就行了吗,对这确实可以,但如果我们写的很多个run()里面都有一个作用相同,名字相同的变量,那么我们每次都得重新写一次,不觉得这样很麻烦吗?所有多线程局部变量就这样出现了。 ThreadLoacl import javax.naming.ldap.PagedResultsControl; cla...

fbher的博客 226

基于YOLOv8的MVTec AD缺陷检测系统设计与实现

速度快,精度高;支持 anchor-free 架构;支持实例分割和图像分类;模块化代码,易于部署与改进;完美兼容 ONNX、TensorRT 等推理框架;官方支持多平台训练和推理(CPU/GPU)。YOLOv8 是工业视觉检测落地非常理想的选择。MVTec AD(Anomaly Detection)数据集包括15类工业对象,每个对象包括多个子类缺陷(例如 “scratch”, “crack”, “hole”)及正常图像。类别缺陷子类bottlecablecapsule。

YOLO 932

ThreadLoacl

目录三. ThreadLoacl 基础二. InheritableThreadLocal三. TransmittableThreadLocal 三. ThreadLoacl 基础 在Java的多线程编程中,为保证多个线程对共享变量的安全访问,通常会使用synchronized来保证同一时刻只有一个线程对共享变量进行操作。 但在有些情况下,synchronized不能保证多线程对共享变量的正确读写。例如类有一个类变量,该类变量会被多个类方法读写,当多线程操作该类的实例对象时,如果线程对类变量有读取、写入操

qq_29799655的博客 223

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

ThreadLocal和InheritableThreadLocal的使用

一、ThreadLocalpublic class Run { public static void main(String[] args) throws InterruptedException{ for(int i=0;i<5;i++){ System.out.println("main="+Tools.t1.get()); Thread.sleep(100); } Thread

NEU_tt的博客 640

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ThreadLoacl源码解析

ThreadLoacl作用与原理?有啥用?怎么用?源码长啥样?有啥Bug?怎么避免?来来来,这里都有~

Leo的博客 167

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

线程池ThreadLoacl传递问题解决办法

起因: JDK的InheritableThreadLocal类可以完成父子线程值的传递。 但对于使用线程池等会缓存线程的组件的情况,线程由线程池创建好,并且线程是缓存起来反复使用的;这时父子线程关系的上下文传递已经没有意义,应用中要做上下文传递,实际上是在把 任务提交给线程池时的上下文传递到 任务执行时。 ThreadLocal和InheritableThreadLocal的局限性: InheritableThreadLocal是ThreadLocal的子类,它们之间的联系是:两者都是线程Thread实例获

qq1170993239的博客 406

【八股】ThreadLocal原理

每个Thread里面都有一个类型为ThreadLocalMap的变量,这个ThreadLocalMap类型的变量其实就是个哈希表,这个哈希表里面的每个Entry的key为ThreadLocal,value为资源对象。最后看到Thread.java源码里的set函数,其实就是找到当前线程的ThreadLocalMap,然后往里面传入key为ThreadLocal,value为资源对象的Entry。

qq_43555854的博客 336

ThreadLocal简单分析与实现原理

ThreadLocal 多线程在访问同一个共享变量的时候容易出现并发的问题,特别是在多个线程对同一个共享变量进行写入的时候,一般都要对共享变量进行适当的同步。 同步的措施一般都是加锁,这就需要使用者对锁有一定的了解,这显然增加了使用者的负担,那么有没有一种方式可以做到,当创建一个变量后,每个线程对其进行访问的时候访问的是自己线程的变量呢?->ThreadLocal ThreadLocal是J...

weixin_41927235的博客 847

Threadlocal在线程池场景下如何传值

我们使用InheritableThreadLocal可以保证在子线程中拿到父线程设置的ThreadLocal的值,它在创建子线程时通过复制父线程的ThreadLocal的值来保证ThreadLocal的值的传递。但是在线程池这种线程复用的场景下,不会每次都创建线程。这就导致了ThreadLocal的值传递不起作用。例如如下例子: static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecuto...

远方的少年 1165

JUC工具类-ThreadLocal

可以通过继承并重写其和方法,在任务执行前后进行全局的清理。: 在任务r即将被线程t执行之前调用。: 在任务r执行完毕后调用(无论正常结束还是异常退出)。// 假设我们知道应用中主要使用的 ThreadLocal 变量// 复用之前的例子// 可能还有其他的 ThreadLocal...@Override// 可以在任务开始前做一些准备,或者确保初始状态干净 (虽然 afterExecute 更常用)@Override// 在任务执行完毕后,清理已知的 ThreadLocal 变量。

左灯右行的爱情 833

ThreadLocal源码解读

1. 背景ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很有问题,包括百度搜索出来的第一篇高访问量博文,说ThreadLocal内部有个map,键为线程对象,太误导人了。ThreadLocal非常适合对Java多线程编程感兴趣的程序员作为入门类阅读,原因两方面:加上注释源码也不过七八百行。结构清晰,代码简洁。本文重点导读ThreadLocal中的嵌套内部类...

Niulx 532

ThreadLocal源码解析以及相关面试题

文章目录ThreadLocal是什么ThreadLocal怎么用,应用场景应用场景ThreadLocal源码分析set方法get方法remove方法InheritableThreadLocalThreadLocal内存泄漏问题 ThreadLocal是什么 ThreadLocal翻译过来就是线程本地,也就是本地线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量,各个线程

孔明的博客 421

解决ThreadLocal 存在的问题

问题:我们写业务代码的时候,有些逻辑是需要在异步线程中去执行,如下图所示,异步线程中,再通过去获取上下文数据,就失效了用应该就行了吧!是 Java 提供的另一个特殊的类,它是的子类。与不同,允许线程将其父线程中的值传递给其子线程。这对于一些需要在父子线程之间共享数据的场景非常有用。其实不然,同样有它的弊端,如果我们在使用线程池的情况下,它就不好使了。

七禾页话的博客 898

java缓存(2、ThreadLocal<T>)

程序图          描述        ThreadCache类是ThreadLocal类的封装,UserManagerServlet请求方法里面创建一个User对象,然后,将对象放到ThreadLocal中,然后,从UserManagerDao获得该对象,再返回给Servlet 程序 ThreadCache package com.tgb.util; impo

张青山 1149
上一篇: 转载---MySQL中的锁(表锁、行锁,共享锁,排它锁,间隙锁)
下一篇: AQS之Node学习
MrMoving
博客等级 码龄10年 54粉丝 145原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值