精华内容
下载资源
问答
  • C# 线程池同步

    千次阅读 2017-04-17 10:56:38
    //锁定,保持同步 ThreadMessage(state.ToString()); Console.Write("Async thread do work!" + i.ToString()); System.Threading.Thread.Sleep(100); Console.WriteLine(state.ToString() ); i++; Monitor....
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    using System.IO;
    using System.Windows;
    using System.Runtime;
    
    namespace Thread
    {
        class Program
        {
            static void Main(string[] args)
            {
                //把线程池的最大值设置为1000
                ThreadPool.SetMaxThreads(1000, 1000);
                ThreadMessage("Start");
                //启动工作者线程
                ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback), "A");
                ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback), "B");
                while (true) ;
            }
    
            private static object _lockQueue = new object();
            public static void AsyncCallback(object state)
            {
                int i=0;
                while (i < 20)
                {
                    
                    System.Threading.Thread.Sleep(1000);
                    Monitor.Enter(_lockQueue); //锁定,保持同步
                    ThreadMessage(state.ToString());
                    Console.Write("Async thread do work!" + i.ToString());
                    System.Threading.Thread.Sleep(100);
                    Console.WriteLine(state.ToString() );
                    i++;
                    Monitor.Exit(_lockQueue); //解锁
                }
            }
            
            //显示线程现状
            public static void ThreadMessage(string data)
            {
                 string message = string.Format("id:{0}   CurrentThreadId is {1}",
                     data, System.Threading.Thread.CurrentThread.ManagedThreadId);
                 Console.WriteLine(message);
            }
        }
    }
    
    
    
    
    
    
    


    当某个线程在Monitor.Entry返回后就获得了对其中_lockQueue的访问权限,其他试图获取_lockQueue 的线程将被阻塞,直到线程调用Monitor.Exit释放_lockQueue 的所有权。这意味着下面三点:
    
    如果_lockQueue 是空闲的,那么第一个调用Entry的线程将立即获得_lockQueue ;
    如果调用Entry的线程已经获准访问_lockQueue ,那么不会阻塞;
    如果调用Entry时_lockQueue 已被其他线程锁定,则线程等待直到_lockQueue 解锁;
    bool b = Monitor.TryEnter(_lockQueue,200); //锁定 时间超出
                    if (b)
                    {
                        ThreadMessage(state.ToString());
                        Console.Write("Async thread do work!" + i.ToString());
                        System.Threading.Thread.Sleep(200);
                        Console.WriteLine(state.ToString());
                        i++;
                    }
                    if(b)
                        Monitor.Exit(_lockQueue); //解锁

    
    
    展开全文
  • java线程面试题1进程与线程的区别进程和线程的通信方式进程之间通信:线程之间通信:创建线程的方式守护线程线程安全的方式线程的sleep和wait线程池线程的同步和并发线程僵死线程关闭的方式 进程与线程的区别 一、每...

    进程与线程的区别

    一、每个进程都有独立的代码和数据空间,线程是进程的一部分,可以看做是轻量级进程,属于同一进程的线程可以共享这个进程的代码和数据空间,每个线程都有独立的运行栈和程序计数器(Program Counter);
    二、进程间的切换会有较大的开销,线程的切换开销较小
    三、进程是资源分配的单位,线程是调度和执行的单位;
    四、一个没有线程的进程可以认为是单线程的,如果一个进程内有多个线程,那么进程的执行过程不是一条线,而是多条线共同执行
    五、在操作系统中同时运行多个程序叫做多进程,在同一应用程序中运行多个线程叫做多线程;
    六、系统在运行的时候会为每个进程分配不同的内存区域,不会给线程分配,线程组只能共享资源。除了CPU外,计算机内部软硬件资源分配与线程无关,线程只是共享它所属进程的资源。

    进程和线程的通信方式

    进程之间通信

    一、管道
    管道,通常指无名管道,是 UNIX 系统IPC最古老的形式;
    二、FIFO
    FIFO,也称为命名管道,它是一种文件类型;
    三、消息队列
    消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识;
    四、信号量
    信号量(semaphore),它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据;
    五、共享内存
    共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。

    线程之间通信

    一、线程同步
    可使用synchronized关键字实现。
    多个线程需要访问同一个共享变量,谁拿到了锁谁就获得了访问权限。比如A线程要用A()方法操作变量,B线程要用B()方法操作同一个变量,此时就需要synchronized来给变量上锁。俗话说皇帝轮流做,今年到我家,轮到A线程,就让A先执行,并且告诉其他线程:锁在我手上,你们谁也不许跟我抢!待A线程执行完后,将锁交给B线程继续执行,此时除B之外的线程都不能执行;
    二、while轮询
    线程A不断地改变条件,线程B不停地通过while语句检测这个条件是否成立,从而实现了线程间的通信。但是这种方式会浪费CPU资源,因为JVM调度器将CPU交给线程B执行时,它只是在不断地测试某个条件是否成立而已;
    三、wait/notify机制
    线程A不断操作变量,而线程B要等到满足某个条件时才能执行,这时,线程B会调用wait()方法进入阻塞状态,不会占用CPU(这样提高了CPU的利用率)。当条件满足时,线程A会调用notify()方法通知线程B并让它进入可运行状态。缺点:比如,线程A先执行,调用了notify()通知B时,此时线程B还执行;当线程B执行并调用wait()时,那它永远就不可能被唤醒了。这说明:通知过早,会打乱程序的执行逻辑。
    四、管道通讯
    管道通信就是使用java.io.PipedInputStream和java.io.PipedOutputStream进行通信。

    创建线程的方式

    一、通过继承Thread类创建线程;
    二、通过实现Runnable接口创建线程;
    三、直接在函数体内创建。

    守护线程

    一个进程中存在多个线程,其中处于后台运行的线程一般为守护线程。调用线程对象的setDaemon()方法并传入true可以将该线程设置为守护线程。当程序中的非守护线程都停止时,java虚拟机就会停止运行,守护线程是能够自动结束自己生命周期的线程。当程序中的主线程关闭,只剩下守护线程时,这些守护线程失去了它们所守护的主线程,人生的意义也将失去,然后这些守护线程就会集体自刎,也就是整个程序都会结束。

    线程安全的方式

    一、使用synchronized锁;
    二、使用volatile锁;
    三、使用Lock锁;
    四、使用jdk1.5并发包中提供的Atomic原子类。

    线程的sleep和wait

    一、sleep()不释放同步锁;wait()释放同步锁;
    二、sleep()可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;wait()可以用notify()直接唤起;
    三、sleep是Thread类的静态方法;wait是Object的方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活调用者;
    四、sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定;而wait()是由某个确定的对象来调用的。其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题。

    线程池

    在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源,在Java中更是如此,所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的。

    线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。线程池中的线程由系统管理,程序员不需要费力于线程管理,可以集中精力处理应用程序任务。

    线程的同步和并发

    在同一时间间隔内有多个线程在同时执行,就是线程的并发。

    多个线程在逻辑上互有前因后果的关系,所以要对他们的执行顺序进行控制和协调,这就是线程同步。

    系统为了提高性能和吞吐量,采用了多线程并发来解决,但同时也引入了线程同步的问题。

    如果线程在时间上能够区分开来,比如线程A先执行,在指定时间后,能够执行完毕或产生我们想要的结果,这时线程B使用线程A的结果作为输入开始执行。像这样通过时间能够严格的加以区分的不是特别复杂的线程关系,可以让线程休眠指定的时间来进行同步。就是采用sleep方法实现同步。

    如果线程在时间上不能区分开,但是在先后顺序上能够区分开,比如线程A先执行,我们不知道它什么时候能够执行完,但是我们知道它必须执行完后线程B才能开始执行。像这样在执行的先后顺序上能够严格的区分开的,而起前一个执行完,后一个才开始的,可以使用join()方法来实现同步。
    如果线程的执行比较复杂,交织在一起,那么只能通过等待和通知,即wait()和notify()方法来实现线程的同步,采用这种方式能够更加灵活的控制线程的步调,但是如果使用不慎的话会容易导致更大的问题。

    线程僵死

    在多线程中,线程会sleep,当程序停止时,线程仍然处于sleep中,就出现了僵死线程。

    线程关闭的方式

    一、通过volatile类型的域来保存取消状态;
    二、通过future的cancel取消线程;
    三、使用interrupt()方法中断当前线程;
    四、使用shutdown()和shutdownNow();
    五、使用stop()方法终止线程。

    展开全文
  • 线程池

    2020-02-29 15:40:19
    线程池

    线程池

    new Thread()弊端

    每次new Thread新建对象,性能差

    线程缺乏统一管理,可能无限的新建线程,相互竞争,有可能占用过多系统资源导致死机

    线程池的好处

    重用已存在的线程,减少对象创建、消亡开销,性能佳

    可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞

    提供定时执行、定期执行、单线程、并发控制能高级功能

    corePoolSize:核心线程数量

    maximumPoolSize:线程最大线程数

    workQueue:阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程中产生重大影响

    三者的关系:如果运行线程数少于corePoolSize,直接创建新线程来处理任务,即使线程池其它线程是空闲的,如果线程池的线程数量大于等于corePoolSize并且小于maxmumPoolSize的时候,则只有当workQueue满的时候,才创建新的线程来处理任务,如果我们设置corePoolSize和maxmumPoolSize值相同时,那么创建线程池大小时固定的,如果有新任务提交,在workQueue还没有满的时候,就把请求放到workQueue里面等待有空闲的线程就从里面取出任务进行处理如果我们的线程数量大于设置的maxmumPoolSize,workQueue也已经满了,那么就通过拒绝策略(rejectHandler)来指定策略来处理任务

    KeepAliveTime:线程没有任务执行时最多保持多久时间终止

    unit:keepAl

    展开全文
  • AsyncTask 初始化线程池 // 参数设置 // We want at least 2 threads and at most 4 threads in the core pool, // preferring to have 1 less than the CPU count to avoid saturating // the CPU with backgrou

    AsyncTask 初始化线程池

         // We want at least 2 threads and at most 4 threads in the core pool,
        // preferring to have 1 less than the CPU count to avoid saturating
        // the CPU with background work
        // 我们希望核心池中至少有2个线程和最多4个线程,最好是比CPU数少1个线程,以避免使CPU背景饱和
        private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
        private static final int KEEP_ALIVE_SECONDS = 30;// 超出的最长等待时间(s)
    
        // 线程创建工厂
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
            public Thread newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };
    
        // 此阻塞队列仅保持由 execute 方法提交的 Runnable 任务。
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(128);
    
        public static final Executor THREAD_POOL_EXECUTOR;// 并行化线程池引用
    
        // 使用 静态代码块 初始化 线程池
        static {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                    sPoolWorkQueue, sThreadFactory);
            threadPoolExecutor.allowCoreThreadTimeOut(true);
            THREAD_POOL_EXECUTOR = threadPoolExecutor;
        }
    

    SerialExecutor

    将并行线程池,改成同步线程池

     // 将并行化线程池 转化为 串行化,实现机制类似递归调用
        private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            Runnable mActive;
    
            public synchronized void execute(final Runnable r) {
                // 向双端队列中添加 Runnable()
                mTasks.offer(new Runnable() { 
                    public void run() {
                        try {
                            r.run();// 编写 run 方法,此时并未执行
                        } finally {
                            scheduleNext();// 执行完一次,寻找下一次,并执行,直到双端队列内无数据
                        }
                    }
                });
                if (mActive == null) { // 如果是第一次执行execute() 此时 mActive = null,执行
                    scheduleNext();
                }
            }
            // 并行化线程池 执行 双端队列中的 Runnable()
            protected synchronized void scheduleNext() {
                if ( (mActive = mTasks.poll())  != null) { // 取出双端队列的末尾 Runnable() 
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }            
        }

    ThreadPoolExecutor

    java1.5提供的 java.util.concurrent 库方法

    // ThreadPoolExecutor 的其一构造方法
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory)
    
    用给定的初始参数和默认被拒绝的执行处理程序创建新的 ThreadPoolExecutor。
    
    参数:
    
    corePoolSize - 池中所保存的线程数,包括空闲线程。
    maximumPoolSize - 池中允许的最大线程数。
    keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
    unit - keepAliveTime 参数的时间单位。
    workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
    threadFactory - 执行程序创建新线程时使用的工厂。
    
    抛出:
    IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。
    NullPointerException - 如果 workQueue 或 threadFactory 为 null

    allowCoreThreadTimeOut

    public void allowCoreThreadTimeOut(boolean value)

    如果在 保持活动时间内 没有任务到达,新任务到达时正在替换(如果需要),则设置 控制核心线程 是 超时 还是 终止 的策略。
    1. 当为 false(默认值)时,由于没有传入任务,核心线程将永远不会中止。
    2. 当为 true 时,适用于 非核心线程 的相同的  保持活动策略也同样适用于核心线程。
    3. 为了避免连续线程替换,保持活动时间在设置为 true 时必须大于 0。
    4. 通常应该在主动使用该池前调用此方法。
    

    参数:
    value - 如果应该超时,则为 true;否则为 false
    抛出:
    IllegalArgumentException - 如果 value 为 true 并且当前保持活动时间不大于 0。
    从以下版本开始:
    1.6

    展开全文
  • 同步容器与线程池

    2020-05-17 19:07:40
    一、同步容器 1、两类 (1)ArrayList -> Vector,Stack (2)HashMap -> HashTable(key,value不能为null) (3)Collections.synchronizedXXX(List、Set、Map) 二、并发容器J.U.C 1、分类 (1)ArrayList ->...
  • 同步半异步线程池

    2018-08-06 11:14:55
    同步半异步线程池:在处理大量并发任务时,为解决传统大量线程创建和销毁将消耗过多的系统资源的问题,通过建立一个线程池在系统中预先创建一定数量的线程,当任务请求到来时从线程池中分配一个预先创建的线程取...
  •   使用1个信标量对象 + 1个CPU屏障 + 1个事件对象共3个内核同步对象实现渲染线程池/大规模线程池管理。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 46,315
精华内容 18,526
关键字:

线程池如何保持同步