精华内容
下载资源
问答
  • —-一进程可以开启的线程受可用内存限制,如果是32位的机器,那么默认一进程有2G的可用内存,而每个线程默认分析1M的栈空间,所以这种情况下理论最线程数在2000多。一解决办法是创建线程时减少线程栈的大小...

    —-

    一个进程可以开启的线程受可用内存限制,如果是32位的机器,那么默认一个进程有2G的可用内存,而每个线程默认分析1M的栈空间,所以这种情况下理论最线程数在2000多个。一个解决办法是创建线程时减少线程栈的大小或是使用64位的系统。64位系统应该可以忽略这个问题了。

    当然受cpu及磁盘速度及物理内存的限制。不用到达上限值,你的机器应该已经是慢如牛车了。

    —-

    有连接就开一个线程的设计和上次一个人说要做一个表格控件,每个单元格都是一个自定义控件,搞得句柄不够用的有的一拼。

    —- 90分

    ClientAccepted里也用socket异步接收,没必要每个连接开一个线程,浪费资源。

    另外32位的系统,我测试过每个进程可以开1800-1900多个线程封顶。超过后,其他线程都会处于等待状态,不会运行,直到有运行的线程退出。

    我之前做过一个采集的项目,下位机设备会主动TCP连接服务器,用socket异步可以保持1W多个TCP连接,如果你每个连接开一个线程,那么你能保持的TCP连接数受到线程数影响,只能不到2000个

    —-

    服务器 不要用同步。

    —-

    客户端同步异步都可以

    —-

    线程是个好多好东西,但不能滥用。

    —-

    32位系统一个进程用户空间为2G,一个线程默认需要1M堆栈(最少128K),可以算一算极限。

    服务器要么异步(系统队列),要么自己处理队列。

    Accept可能没必要异步,用一个线程同步处理更好。

    另外活动线程太多的话,频繁的上下文切换很耗CPU。

    —-

    可以开N多个,N和你的内存大小相关,但是后面的都会挂起。

    —- 10分

    socket.Listen(10000);//不知道是干啥的 就写10000了

    看方法说明啊

    BeginAccept并不是你想的那样执行一次开一个线程,实际情况是bind一个线程池线程,异步执行完后

    会放回线程池,池内会保持几个(默认与CPU数量有关)空闲线程活动(减小频繁创建-销毁线程的开销)

    池最大可运行的线程数量,可以通过System.Threading.ThreadPool.GetMaxThreads获取,相应地还有个Set方法,

    一般情况不需要考虑最大数量(真到那时候加服务器吧),有些情况通过设置最少活动线程SetMinThreads来提高性能

    —-

    队列!!!!!!!

    —-

    开多少线程 和你CPU 有关系···

    —-

    引用 4 楼 xiaozhu39505 的回复:

    我之前做过一个采集的项目,下位机设备会主动TCP连接服务器,用socket异步可以保持1W多个TCP连接

    现在我的需求就跟你这个差不多.. 1W多个 如果在多了呢? 比如100W个下位机. 怎么办?

    —-

    引用 16 楼 diaodiaop 的回复:

    Quote: 引用 4 楼 xiaozhu39505 的回复:

    我之前做过一个采集的项目,下位机设备会主动TCP连接服务器,用socket异步可以保持1W多个TCP连接

    现在我的需求就跟你这个差不多.. 1W多个 如果在多了呢? 比如100W个下位机. 怎么办?

    百万级别的这个就得做均衡负载了,这个可不是靠程序优化就能解决的

    —-

    引用 16 楼 diaodiaop 的回复:

    现在我的需求就跟你这个差不多.. 1W多个 如果在多了呢? 比如100W个下位机. 怎么办?

    没有活动的异步连接,基本上只是消耗内存而已。

    —-

    没有限制,但开多了很慢

    —-

    微软操作系统的线程一共才几百个。

    你想想你的程序开多了会在怎样

    —-

    xiaozhu39505 小辉?

    呵呵,在这里见到你了,好久没联系了,当时我们用 socket异步修改程序后续的情况我不是很清楚了,实际运行后对服务器的占用率有多大?

    现在我又一次面对当时的情况了,是一个手机端即时通讯程序,需要连几万个客户端

    —-

    引用 22 楼 gxch 的回复:

    xiaozhu39505 小辉?

    呵呵,在这里见到你了,好久没联系了,当时我们用 socket异步修改程序后续的情况我不是很清楚了,实际运行后对服务器的占用率有多大?

    现在我又一次面对当时的情况了,是一个手机端即时通讯程序,需要连几万个客户端

    哈哈,谷哥吗?当时只是测试的可连接数,没有具体测试服务器负载情况。socket异步里就使用了完成端口,用异步是效率最高的,至于负载情况,还得具体测试才行哈

    —-

    貌似有线程池

    展开全文
  • 所以我的目标是让do_something()函数启动自己的线程,以便do_something()可以并行运行,而不必等待前一完成.问题是它似乎不是多线程(意味着一个线程在另一个线程开始之前完成).for i in range(len(array_of_letters)...

    所以我的目标是让do_something()函数启动自己的线程,以便do_something()可以并行运行,而不必等待前一个完成.问题是它似乎不是多线程(意味着一个线程在另一个线程开始之前完成).

    for i in range(len(array_of_letters)):

    if i == "a":

    t = threading.Thread(target=do_something())

    print "new thread started : %s"%(str(threading.current_thread().ident))

    t.start()

    我在do_something()函数中也有一个current_thread().ident,但似乎启动的线程的标识与运行python脚本的主线程相同.我认为我的方法不正确.

    解决方法:

    这是一个常见的,容易出错的错误.

    target = do_something()只是在主线程中一次执行你的函数,并将None(你想要的函数的返回值)作为目标函数传递给线程,它不会触发任何可见的错误;但也没有做任何事.

    你必须传递实际的功能而不是结果:

    t = threading.Thread(target=do_something)

    会更好

    标签:python,multithreading

    来源: https://codeday.me/bug/20191002/1844523.html

    展开全文
  • 1. 如何创建Looper? Looper的构造方法为private,所以不能直接使用其构造方法创建。...要想在当前线程创建Looper,需使用Looper的prepare方法,Looper.prepare()。 如果现在要我们来实现Looper.prepare

    1. 如何创建Looper?

    Looper的构造方法为private,所以不能直接使用其构造方法创建。

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

    要想在当前线程创建Looper,需使用Looper的prepare方法,Looper.prepare()。
    如果现在要我们来实现Looper.prepare()这个方法,我们该怎么做?我们知道,Android中一个线程最多只能有一个Looper,若在已有Looper的线程中调用Looper.prepare()会抛出RuntimeException(“Only one Looper may be created per thread”)。面对这样的需求,我们可能会考虑使用一个HashMap,其中Key为线程ID,Value为与线程关联的Looper,再加上一些同步机制,实现Looper.prepare()这个方法,代码如下:

    public class Looper {
    
        static final HashMap<Long, Looper> looperRegistry = new HashMap<Long, Looper>();
    
        private static void prepare() {
            synchronized(Looper.class) {
                long currentThreadId = Thread.currentThread().getId();
                Looper l = looperRegistry.get(currentThreadId);
                if (l != null)
                    throw new RuntimeException("Only one Looper may be created per thread");
                looperRegistry.put(currentThreadId, new Looper(true));
            }
        }
        ...
    }

    上述方法对Looper.class对象进行了加锁,这些加锁开销有可能造成性能瓶颈。
    有没有更好的方法实现Looper.prepare()方法?看一看Android的中Looper的源码。

    public class Looper {
    
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
        public static void prepare() {
           prepare(true);
        }
    
        private static void prepare(boolean quitAllowed) {
           if (sThreadLocal.get() != null) {
               throw new RuntimeException("Only one Looper may be created per thread");
           }
           sThreadLocal.set(new Looper(quitAllowed));
        }
        ...
    }

    prepare()方法中调用了ThreadLocal的get和set方法,然而整个过程没有添加同步锁,Looper是如何实现线程安全的?

    2.百度转载的分析:

    新创建的线程里进行 Looper.prepare() 操作,因为 Looper 的构造方法是私有的

     

    所以要想创建 Looper 对象,还需使用 prepare() 方法创建

     

     

    而 prepare() 方法的实质则是:

    创建 Looper 对象将创建好的 Looper 对象存储到 ThreadLocal 对象里注意 : ThreadLocal 对象在创建 Looper 的时候创建的。

     

    注意看 ThreadLocal 存储 Looper 的处理方式,是保证 ThreadLocal 里没有其他的 Looper,只允许有一份 Looper。

    这就是为什么同一个 Thread 线程里只能有一个 Looper 对象的原因。

    这就解答了题目的问题。

    接下来,我们来看一下为什么 Looper 要由 ThreadLocal 保管呢?

     

     

    这是 ThreadLocal 源码中对其的介绍,翻译过来就是 ThreadLocal 提供了针对于单独的线程的局部变量,并能够使用 set()、get() 方法对这些变量进行设置和获取,并且能够保证这些变量与其他线程相隔离。

    换句话说,通过使用 threadLocal 存储对象,线程和线程之间的彼此的数据就会隔离起来,从而保证了彼此线程的数据安全和独立性。

    我们来看一下 ThreadLocal 的 get 方法:

     

    由上图我们看到,get 方法是通过当前的线程thread,取到一个 ThreadLocalMap 对象(这个就把他当做 map 集合对待即可)。

    如果得到的map 是空,则进行这个 map 的初始化:

    setInitialValue()。

     

     

    而初始化的方式也很简单,就是创建一个以 ThreadLocal 自身为 key,存入的对象为 value 的 ThreadLocalMap 对象,然后把这个 ThreadLocalMap 存到线程 thread 里面(方便与线程进行绑定)。

    如果得到的 map 不为空

     

    则从 ThreadLocalMap 中获取对应的存储对象,如果没有向 ThreadLocal 里调用 set() 方法,这个时候调用 get() 方法返回的值就是 null。

    回想一下 Looper 的 prepare() 方法

     

    就很符合这个逻辑。

    prepare() 方法会判断 threadLocal 的 get() 方法,如果返回值不为 null,说明调用过了 threadLocal 的set() 方法了。

    此时 set 方法其实也无需再看了,无非就是将需要存储的对象当做value,当前的 threadLocal 的引用当做key,存储进 threadLocalMap 里面,然后将其指向线程thread。

    所以总述一下,Looper 是通过利用 ThreadLocal 的数据隔离性将 Looper 对象存储在对应的线程中,保证每一个线程只能创建一个 Looper 对象。

    参考地址:https://baijiahao.baidu.com/s?id=1672811852535456858&wfr=spider&for=pc

    3. ThreadLocal

    ThreadLocal位于java.lang包中,以下是JDK文档中对该类的描述

    Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads share the same ThreadLocal object, but each sees a different value when accessing it, and changes made by one thread do not affect the other threads. The implementation supports null values.

    大致意思是,ThreadLocal实现了线程本地存储。所有线程共享同一个ThreadLocal对象,但不同线程仅能访问与其线程相关联的值,一个线程修改ThreadLocal对象对其他线程没有影响。

    ThreadLocal为编写多线程并发程序提供了一个新的思路。如下图所示,我们可以将ThreadLocal理解为一块存储区,将这一大块存储区分割为多块小的存储区,每一个线程拥有一块属于自己的存储区,那么对自己的存储区操作就不会影响其他线程。对于ThreadLocal<Looper>,则每一小块存储区中就保存了与特定线程关联的Looper。
    这里写图片描述

    3. ThreadLocal的内部实现原理

    3.1 Thread、ThreadLocal和Values的关系

    Thread的成员变量localValues代表了线程特定变量,类型为ThreadLocal.Values。由于线程特定变量可能会有多个,并且类型不确定,所以ThreadLocal.Values有一个table成员变量,类型为Object数组。这个localValues可以理解为二维存储区中与特定线程相关的一列。
    ThreadLocal类则相当于一个代理,真正操作线程特定存储区table的是其内部类Values。
    这里写图片描述
    这里写图片描述

    3.2 set方法

    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }
    
    Values values(Thread current) {
        return current.localValues;
    }

    既然与特定线程相关,所以先获取当前线程,然后获取当前线程特定存储,即Thread中的localValues,若localValues为空,则创建一个,最后将value存入values中。

    void put(ThreadLocal<?> key, Object value) {
        cleanUp();
    
        // Keep track of first tombstone. That's where we want to go back
        // and add an entry if necessary.
        int firstTombstone = -1;
    
        for (int index = key.hash & mask;; index = next(index)) {
            Object k = table[index];
    
            if (k == key.reference) {
                // Replace existing entry.
                table[index + 1] = value;
                return;
            }
    
            if (k == null) {
                if (firstTombstone == -1) {
                    // Fill in null slot.
                    table[index] = key.reference;
                    table[index + 1] = value;
                    size++;
                    return;
                }
    
                // Go back and replace first tombstone.
                table[firstTombstone] = key.reference;
                table[firstTombstone + 1] = value;
                tombstones--;
                size++;
                return;
            }
    
            // Remember first tombstone.
            if (firstTombstone == -1 && k == TOMBSTONE) {
                firstTombstone = index;
            }
        }
    }

    从put方法中,ThreadLocal的reference和值都会存进table,索引分别为index和index+1。
    对于Looper这个例子,
    table[index] = sThreadLocal.reference;(指向自己的一个弱引用)
    table[index + 1] = 与当前线程关联的Looper。

    3.3 get方法

    public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }
        } else {
            values = initializeValues(currentThread);
        }
    
        return (T) values.getAfterMiss(this);
    }

    首先取出与线程相关的Values,然后在table中寻找ThreadLocal的reference对象在table中的位置,然后返回下一个位置所存储的对象,即ThreadLocal的值,在Looper这个例子中就是与当前线程关联的Looper对象。

    从set和get方法可以看出,其所操作的都是当前线程的localValues中的table数组,所以不同线程调用同一个ThreadLocal对象的set和get方法互不影响,这就是ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。

    4. ThreadLocal背后的设计思想Thread-Specific Storage模式

    Thread-Specific Storage让多个线程能够使用相同的”逻辑全局“访问点来获取线程本地的对象,避免了每次访问对象的锁定开销。

    4.1 Thread-Specific Storage模式的起源

    errno机制被广泛用于一些操作系统平台。errno 是记录系统的最后一次错误代码。对于单线程程序,在全局作用域内实现errno的效果不错,但在多线程操作系统中,多线程并发可能导致一个线程设置的errno值被其他线程错误解读。当时很多遗留库和应用程序都是基于单线程编写,为了在不修改既有接口和遗留代码的情况下,解决多线程访问errno的问题,Thread-Specific Storage模式诞生。

    4.2 Thread-Specific Storage模式的总体结构

    这里写图片描述

    线程特定对象,相当于Looper。
    线程特定对象集包含一组与特定线程相关联的线程特定对象。每个线程都有自己的线程特定对象集。相当于ThreadLocal.Values。线程特定对象集可以存储在线程内部或外部。Win32、Pthread和Java都对线程特定数据有支持,这种情况下线程特定对象集可以存储在线程内部。
    线程特定对象代理,让客户端能够像访问常规对象一样访问线程特定对象。如果没有代理,客户端必须直接访问线程特定对象集并显示地使用键。相当于ThreadLocal<Looper>。

    从概念上讲,可将Thread-Specific Storage的结构视为一个二维矩阵,每个键对应一行,每个线程对应一列。第k行、第t列的矩阵元素为指向相应线程特定对象的指针。线程特定对象代理和线程特定对象集协作,向应用程序线程提供一种访问第k行、第t列对象的安全机制。注意,这个模型只是类比。实际上Thread-Specific Storage模式的实现并不是使用二维矩阵,因为键不一定是相邻整数。
    这里写图片描述

    展开全文
  • 主要介绍了Java虚拟机最多支持多少个线程的问题,从StackOverflow上摘录而来,需要的朋友可以参考下
  • Java虚拟机最多支持多少个线程?跟虚拟机开发商有关么?跟操作系统呢?还有其他的因素吗? 这取决于你使用的CPU,操作系统,其他进程正在做的事情,你使用的Java的版本,还有其他的因素。我曾经见过一台...

    在StackOverflow提了这样一个问题:

    Java虚拟机最多支持多少个线程?跟虚拟机开发商有关么?跟操作系统呢?还有其他的因素吗?


    Eddie的回答:

    这取决于你使用的CPU,操作系统,其他进程正在做的事情,你使用的Java的版本,还有其他的因素。我曾经见过一台Windows服务器在宕机之前有超过6500个线程。当然,大多数线程什么事情也没有做。一旦一台机器上有差不多6500个线程(Java里面),机器就会开始出问题,并变得不稳定。

    以我的经验来看,JVM容纳的线程与计算机本身性能是正相关的。

    当然了,你要有足够的本机内存,并且给Java分配了足够的内存,让每个线程都可以拥有栈(虚拟机栈),可以做任何想做的事情。任何一台拥有现代CPU(AMD或者是Intel最近的几代)和1-2G内存(取决于操作系统)的机器很容易就可以支持有上千个线程的Java虚拟机。

    如果你需要一个更精确的答案,最好是自己做压测。

    Charlie Martin的回答:

    这里有很多的参数(可以设置)。对于特定的虚拟机,都会有自己的运行时参数。(最大线程数)一定程度上由操作系统决定的:底层的操作系统要给线程提供哪些支持?施加哪些限制?虚拟机使用的是原生的操作系统的线程还是red thread或者green thread?

    操作系统提供的支持是另一个问题。如果你向下面这样写Java程序:

    复制代码代码如下:

    class DieLikeADog {
          public static void main(String[] argv){
              for(;;){
                 new Thread(new SomeRunaable).start();
              }
          }
     }

    (不要抱怨语法细节,这才刚刚开始)那你当然希望能得到成百上千个运行的线程。但是,创建一个线程的成本是相对较大的,(过多线程)调度的开销会变得突出。能否让这些线程做有用的事情还不确定。

    升级版

    好了,迫不及待了!下面是我的一个加了点润色的小的测试程序:

    复制代码代码如下:
    public class DieLikeADog {
        private static Object s = new Object();
        private static int count = 0;
        public static void main(String[] argv){
            for(;;){
                new Thread(new Runnable(){
                        public void run(){
                            synchronized(s){
                                count += 1;
                                System.err.println("New thread #"+count);
                            }
                            for(;;){
                                try {
                                    Thread.sleep(1000);
                                } catch (Exception e){
                                    System.err.println(e);
                                }
                            }
                        }
                    }).start();
            }
        }
    }

    在Intel的OS/X 10.5.6系统上,Java 5的输出如下:
    复制代码代码如下:

    New thread #2547
    New thread #2548
    New thread #2549
    Can't create thread: 5
    New thread #2550
    Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
            at java.lang.Thread.start0(Native Method)
            at java.lang.Thread.start(Thread.java:592)
            at DieLikeADog.main(DieLikeADog.java:6)

    benjismith的回答:

    读了Charlie Martin的回复以后,我很想知道堆内存的大小是否能够给创建的线程数带来不同,然后我就被结果惊呆了:在Vista Home Premium SP1系统上,使用JDK 1.6.0_11,设置堆内存的大小从2M到1024M来执行Charlie的测试程序。比如:创建2M的堆内存,我使用的虚拟机参数是:-Xms2m -Xmx2m.

    下面是我的测试结果:

    复制代码代码如下:
    2 mb --> 5744 threads
    4 mb --> 5743 threads
    8 mb --> 5735 threads
    12 mb --> 5724 threads
    16 mb --> 5712 threads
    24 mb --> 5687 threads
    32 mb --> 5662 threads
    48 mb --> 5610 threads
    64 mb --> 5561 threads
    96 mb --> 5457 threads
    128 mb --> 5357 threads
    192 mb --> 5190 threads
    256 mb --> 5014 threads
    384 mb --> 4606 threads
    512 mb --> 4202 threads
    768 mb --> 3388 threads
    1024 mb --> 2583 threads

    所以,堆的大小确实很重要。但是,堆大小和最大线程数却是呈反比例关系。
    这太诡异了!

    Neil Coffey的回答:

    绝对理论上的最大线程数是进程的用户地址空间除以线程栈的大小(现实中,如果内存全部给线程栈使用,就不会有能运行的程序了)。因此,以32位Windows系统为例,每一个进程的用户地址空间是2G,假如每个线程栈的大小是128K,最多会有16384(=2*1024*1024 / 128)个线程。实际在XP系统上,我发现大约能启动13000个线程。

    然后,我认为,你的问题本质上是:(a)你是否可以在你的代码中有效的管理许多的线程,不让他们做很显然是愚蠢的事情(比如:让他们在同一个object对象上等待随后被调用notifyAll()…),(b)操作系统是否可以有效地管理这许多线程。基本上来说,如果(a)的答案是”yes”的话,(b)的答案也是”yes”。

    很巧的是,你可以在Thread的构造函数中设置线程栈的大小,但是,你不需要也不应该把这个和虚拟机参数弄混淆。

    展开全文
  • Android如何保证一个线程最多只能有一Looper?

    万次阅读 多人点赞 2016-04-01 21:04:59
    我们知道,Android中一个线程最多只能有一Looper,若在已有Looper的线程中调用Looper.prepare()会抛出RuntimeException(“Only one Looper may be created per thread”)。面对这样的需求,我们可能会考虑使用一...
  • JAVA最多支持多少个线程

    千次阅读 2015-07-24 16:05:42
    1. java的线程开启,默认的虚拟机会分配1M的内存,但是在4G的windows上线程最多也就开到300多 ,是因为windows本身的一些限制导致。 2. 虚拟机给每线程分配的内存(栈空间)是由虚拟机参数-Xss来指定的,在不同...
  • 可不可以在一进程内开130个线程?楼主invaders(不负少年头)2001-04-28 14:19:00 在 VC/MFC / 进程/线程/DLL 提问稳定吗?问题点数:86、回复次数:32Top1 楼ytweiwei(又穷又丑农村户口!!!!)回复于 2001-04-28 14:...
  • Java虚拟机最多支持多少个线程

    千次阅读 2019-06-18 15:29:27
    McGovernTheory在StackOverflow提了这样一问题:Java虚拟机最多支持多少个线程?跟虚拟机开发商有关么?跟操作系统呢?还有其他的因素吗? Eddie的回答: 这取决于你使用的CPU,操作系统,其他进程正在做的...
  • Java虚拟机最多支持多少个线程?跟虚拟机开发商有关么?跟操作系统呢?还有其他的因素吗? Eddie的回答: 这取决于你使用的CPU,操作系统,其他进程正在做的事情,你使用的Java的版本,还有其他的因素。我曾经见...
  • McGovernTheory在StackOverflow提了这样一问题:Java虚拟机最多支持多少个线程?跟虚拟机开发商有关么?跟操作系统呢?还有其他的因素吗?Eddi...
  • 进程最多多少线程? 我们都知道进程的概念,它是CPU分配资源的载体,是程序运行的实例;也知道线程的概念,它是程序执行的最小单元,是进程中的一实体用来执行程序,一进程中有多个线程。 既然如此,...
  • 进程最多创建多少个线程

    千次阅读 2018-10-10 23:02:38
    最近,在做一关于聊天服务器的项目,其中遇到了一问题,那就是一进程可以产生多少个线程呢? 开始各种想象,会和不同平台,不同系统相关,网上很多大佬说是1024,也有256。 与其无端猜测,不如动手测试...
  • 以下是对在linux环境下一进程最多能有多少个线程进行了介绍,需要的朋友可以过来参考下
  • Java虚拟机最多支持多少个线程?跟虚拟机开发商有关么?跟操作系统呢?还有其他的因素吗? Eddie的回答: Charlie Martin的回答: 升级版 benjismith的回答: Neil Coffey的回答: 最后 关于JVM系列面试知识点...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 286,222
精华内容 114,488
关键字:

线程最多多少个