精华内容
下载资源
问答
  • 2018-08-07 16:48:58

    掌握Android的多线程通信机制,我们首先应该掌握Android中进程与线程是什么。
    1. 进程
    在Android中,一个应用程序就是一个独立的进程(应用运行在一个独立的环境中,可以避免其他应用程序/进程的干扰)。一般来说,当我们启动一个应用程序时,系统会创建一个进程(从Zygote中fork出来的,这个进程会有独立的ID),并为这个进程创建一个主线程(UI线程),然后就可以运行MainActivity了,应用程序的组件默认都是运行在它的进程中,但我们可以通过指定应用的组件(四大组件)的运行进程:android:process来让组件运行在不同的进程中;让组件运行在不同的进程中,会带来好处,也会带来坏处:
    好处是:因为每一个应用程序(也就是每一个进程)都会有一个内存预算,所有运行在这个这个进程中的程序使用的总内存不能超过这个值,让组件运行不同的进程中,可以让主进程可以拥有更多的空间资源。
    坏处是:每个进程都会有自己的虚拟机实例,因此让在进程间共享一些数据变得困难;(当然,我们可以采用多进程间的通信来实现数据的共享)
    当我们的应用程序比较大,需要的内存资源比较多时(也就是用户会抱怨应用经常出现OutOfMemory时),可以考虑使用多进程
    2. 线程
    在Java中,线程会有那么几种状态:创建,就绪,运行,阻塞,死亡。当应用程序有组件在运行时,UI线程是处于运行状态的。默认情况下,应用的所有组件的操作都是在UI线程里完成的,包括响应用户的操作(触摸,点击等),组件生命周期方法的调用,UI的更新等。因此如果UI线程处理阻塞状态时(在线程里做一些耗时的操作,如网络连接等),就会不能响应各种操作,如果阻塞时间达到5秒,就会让程序处于ANR(application not response)状态,这时用户就可能退出你的应用甚至卸载你的应用,这是我们不能接受的。 这时,有人就会说,我们在其他线程中更新UI不就可以了吗,就不会导致UI线程处于阻塞状态了。但答案是否定的。

    因为Android的UI线程是非线程安全的,应用更新UI,是调用invalidate()方法来实现界面的重绘,而invalidate()方法是非线程安全的,也就是说当我们在非UI线程来更新UI时,可能会有其他的线程或UI线程也在更新UI,这就会导致界面更新的不同步。因此我们不能在非UI主线程中做更新UI的操作。也就是说我们在使用Android中的线程时,要保证:
    不能阻塞UI主线程,也就是不能在UI主线程中做耗时的操作,如网络连接,文件的IO;
    只能在UI主线程中做更新UI的操作;
    在Android中,我们把除UI线程外的,其他所有的线程都叫做工作线程,也就是说Android只会存在两种线程:UI主线程(UI thread)和工作线程(work thread).我们不能在UI主线程中做耗时的操作,因此我们可以把耗时的操作放在另一个工作线程中去做。操作完成后,再通知UI主线程做出相应的响应。这就需要掌握线程间通信的方式了。在Android中提供了两种线程间的通信方式:一种是AsyncTask机制,另一种是Handler机制

    Android线程间通信方式之Handler机制;
    使用Handler机制,也就是通过使用Handler,Looper,MessageQueue,和Message这几个类协调来完成。我们先来看使用Handler机制完成线程间通信的原理,然后再详细介绍这几个类;先看一下这几个类的作用:
    Handler,发送和处理Message对象和Runnable对象;
    Looper,用于从MessageQueue中取出消息(Message)对象,并发送给Handler处理;
    MessageQueue,消息队列,用于存放通过Handler发布的消息;
    Message,消息的类型,里面包含几个实例对象:
    what,用户定义的int型消息代码,用来描述消息;
    obj,随消息发送的用户用户指定对象;
    target,处理消息的Handler;
    一个Handler对象仅与一个Looper相关联,一个Message也仅与一个目标Handler对象相关联,一个Looper对象拥有一个MessageQueue。但多个不同的Handler对象可以与同一个对象相关联,也就是说多个Handler可以共享一个MessageQueue,从而达到消息共享的目的,这也是Android通过Handler机制实现多线程间通信的核心原理;
    上面说到Handler对象仅与一个Looper相关联,那么这个关联是什么时候实现的呢?答案是:Handler对象创建的时候。UI主线程在创建的时候就会拥有一个handler对象和一个Looper对象(工作线程需要自己调用Looper.prepare()来创建一个Looper对象),然后任何在UI主线程中创建的Handler对象默认都会与UI主线程的Looper对象相关联(Handler对象创建的时候,会与这个线程的Looper对象相关联)。进而我们就可以把在UI主线程中创建的Handler对象传递给(依赖注入或引用形式)工作线程,那么在工作线程中用这个Handler对象处理的消息就是在UI主线程的MessageQueue中处理的,从而达到线程间通信的目的。
    了解了使用Handler机制来实现Android线程间异步通信的原理,下面我们再来详细了解下这四个核心类;
    2.2.1 Handler
    Handler,继承自Object类,用来发送和处理Message对象或Runnable对象;Handler在创建时会与当前所在的线程的Looper对象相关联(如果当前线程的Looper为空或不存在,则会抛出异常,此时需要在线程中主动调用Looper.prepare()来创建一个Looper对象)。使用Handler的主要作用就是在后面的过程中发送和处理Message对象和让其他的线程完成某一个动作(如在工作线程中通过Handler对象发送一个Message对象,让UI线程进行UI的更新,然后UI线程就会在MessageQueue中得到这个Message对象(取出Message对象是由其相关联的Looper对象完成的),并作出相应的响应)。
    Handler用post体系来完成发送Runnable对象的工作,用sendMessage体系 来完成发送Message对象的工作;
    post体系,允许把一个Runnable对象发送到消息队列中,它的方法有:post(Runnable),postDelayed(Runnable,long),postAtTime(Runnable,long);
    sendMessage体系,把Message对象发送给消息队列,它的方法有:sendEmptyMessage(int),sendMessage(Message),sendMessageDelayed(Message,long),sendMessageAtTime(Message,long);
    如果Handler是通过post体系将Runnable对象发送到MessageQueue队列中,则这个Runnable对象的run()方法是运行在Handler对象创建时所在线程;
    如果Handler是通过sendMessage体系将Message发送到MessageQueue中,则需要重写handleMessage()方法来获取工作线程传递过来的Message对象,handleMessage()方法是工作在Handler对象建立时所在的线程的(一般我们会在UI线程中建立Handler对象,然后传递给子线程,此时这个Handler对象的handleMessage()方法就是运行在UI主线程中的);
    2.2.2 Message
    Message用来定义一个包含任意数据的消息对象,这个消息对象是可以被发送给Handler处理的。我们最好通过Message.obtain()和Handler.obtatinMessage()来得到一个Message对象(通过这两个方法得到的对象是从对象回收池中得到,也就是说是复用已经处理完的Message对象,而不是重新生成一个新对象),如果通过Message的构造方法得到一个Message对象,则这个Message对象是重新生成的(不建议使用这种方法)。
    Message对象用来封装需要传递的消息,Message的数据结构为:
    Message{
    int arg1;//如果我们只需要存储一些简单的Integer数据,则可通过设置这个属性来传递
    int agr2;//使用同arg1
    Object obj; //设置需要发送给接收方的对象,这个对象需要实现序列化接口
    int what; //描述这个消息的标识;
    //设置与这个消息对应的任意数据,这个数据是用Bundle封装的;
    void setData(Bundle data);
    Bundle getData(); 得到与这个消息对应的数据信息;
    //省略了方法和可选的属性
    ……
    如果需要通过Message对象传递一些比较复杂的数据,则需要使用将数据封装成Bundle对象,然后通过setData(Bundle)方法来传递,用getData()来得到与这个消息对应的数据(这方法与设置Message的Object 属性作用相同);
    2.2.3 MessageQueue
    MessageQueue保存由Looper调度的消息列表,消息通过与Looper相关联的Handler对象添加进MessageQueue。
    2.2.4 Looper
    Looper为线程运行一个消息的循环队列,主要就是为了完成MessageQueue与Handler交互的功能;需要注意的是线程默认并不会给我们提供一个一个Looper实例来管理消息队列,我们需要在线程中主动调用Looper.prepare()方法来实例化一个Looper对象,用于管理消息队列;Looper对象会不断去判断MessageQueue是否为空,如果不空,则将Message取出给相应的Handler进行处理;如果MessageQueue为空,则Looper对象会进行阻塞状态,直到有新的消息进入MessageQueue;
    其实,说白了,Android中通过Handler机制来异步处理多线程间的通信就是多个线程间共享一个MessageQueue,工作线程将消息发送到MessageQueue,然后UI线程或其他工作线程在MessageQueue在取出消息,进行相应的处理;

    更多相关内容
  • 多线程的面试题,从基础到深入系列,收集的其它同仁的,实用性强
  • 2)使用singal/slot机制,把数据从一个线程传递到另外一个线程。 代码中是针对信号和槽机制,进行描述和演示。环境是qt5.9 1、传递int参数(主线程与子线程) 2、传递自定义参数(主线程与子线程) 3、传递自定义...
  •  多线程通信,其实是多个线程操操作同一个资源,但是操作方式不同。典型实例有生产者和消费者,本文也通过实例来分析线程等待唤醒机制。  1、相关API介绍  public final void notify()  唤醒在此对象监视...
  • Python 多线程及线程间通信

    千次阅读 多人点赞 2020-09-05 17:27:00
    作者:billy 版权声明:著作权归作者所有,...由于线程是操作系统直接支持的执行单元,因此,高级语言(如 Python、Java 等)通常都内置多线程的支持。Python 的标准库提供了两个模块:_thread 和 threading,_thread

    作者:billy
    版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

    创建线程

    线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每个线程并行执行不同的任务。

    由于线程是操作系统直接支持的执行单元,因此,高级语言(如 Python、Java 等)通常都内置多线程的支持。Python 的标准库提供了两个模块:_thread 和 threading,_thread 是低级模块,threading 是高级模块,对 _thread 进行了封装。绝大多数情况下,我们只需要使用 threading 这个模块。

    1. 使用 threading 模块创建线程
      threading 模块提供了一个 Thread 类来代表一个线程对象,其语法如下:
      Thread(group [, target [, name [, args [, kwaegs]]]])
      group:参数未使用,值始终为 None;
      target:表示一个可调用对象,线程启动时,run() 方法将调用此对象,默认值为 None,表示不调用任何内容;
      name:为当前线程名称,默认创建一个 Thread-N 格式的唯一名称;
      args:表示传递给 target 函数的参数元组;
      kwargs:表示传递给 target 函数的参数字典;

    对比发现,Thread 类和上一章节中的 Process 类的方法基本相同,直接上案例:

    import threading, time
    
    def process():
        for i in range(3):
            time.sleep(1)
            print("thread name is %s" % threading.current_thread().name)
    
    if __name__ == '__main__':
        print("---主线程开始---")
        threads = [threading.Thread(target=process) for i in range(4)]  # 创建 4 个线程,存入列表
        for th in threads:
            th.start()
        for th in threads:
            th.join()
        print("---主线程结束---")
    

    上述例子的运行结果为:

    ---主线程开始---
    thread name is Thread-3
    thread name is Thread-2
    thread name is Thread-1
    thread name is Thread-4
    thread name is Thread-4
    thread name is Thread-1
    thread name is Thread-3
    thread name is Thread-2
    thread name is Thread-1
    thread name is Thread-4
    thread name is Thread-2
    thread name is Thread-3
    ---主线程结束---
    
    1. 使用 Thread 子类创建线程
      Thread 线程类和 Process 进程类使用方式非常相似,也可以通过定义一个子类,使其继承 Thread 线程类来创建线程。

    示例:

    import threading, time
    
    class SubThread(threading.Thread):
        def run(self):
            for i in range(3):
                time.sleep(1)
                msg = "子线程" + self.name + "执行,i = " + str(i)    # name 为属性中保存的当前线程的名字
                print(msg)
    
    if __name__ == '__main__':
        print("---主线程开始---")
        t1 = SubThread()
        t2 = SubThread()
        t1.start()  # start() 方法开启线程,会自动调用 run() 方法
        t2.start()
        t1.join()
        t2.join()
        print("---主线程结束---")
    

    上述例子的运行结果为:

    ---主线程开始---
    子线程Thread-2执行,i = 0
    子线程Thread-1执行,i = 0
    子线程Thread-2执行,i = 1
    子线程Thread-1执行,i = 1
    子线程Thread-1执行,i = 2
    子线程Thread-2执行,i = 2
    ---主线程结束---
    

    互斥锁

    在一个进程内的所有线程是共享全局变量的,由于线程可以对全局变量随意修改,这就可能造成多线程之间全局变量的混乱。这就需要用到互斥锁(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域

    互斥锁为资源引入一个状态:锁定和非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为 “锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成 “非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性

    在 threading 模块中使用 Lock 类可以方便处理锁定。Lock 类有两个方法:acquire() 锁定和 release() 释放锁。语法如下:

    mutex = threading.Lock()		# 创建锁
    mutex.acquire([blocking])		# 锁定
    mutex.release()				# 释放锁
    

    示例:

    from threading import Thread, Lock
    import time
    
    n = 100 # 共 100 张电影票
    
    def task():
        global n
        mutex.acquire()     # 上锁
        temp = n            # 赋值给临时变量
        time.sleep(0.5)     # 睡眠 0.5 秒
        n = temp - 1        # 数量减 1
        print("购买成功,剩余 %d 张电影票" % n)
        mutex.release()     # 释放锁
    
    if __name__ == '__main__':
        mutex = Lock() 
        list = []
        for i in range(10):
            th = Thread(target=task)
            list.append(th)
            th.start()
        for th in list:
            th.join()
    

    上述例子的运行结果为:

    购买成功,剩余 99 张电影票
    购买成功,剩余 98 张电影票
    购买成功,剩余 97 张电影票
    购买成功,剩余 96 张电影票
    购买成功,剩余 95 张电影票
    购买成功,剩余 94 张电影票
    购买成功,剩余 93 张电影票
    购买成功,剩余 92 张电影票
    购买成功,剩余 91 张电影票
    购买成功,剩余 90 张电影票
    

    使用队列在线程间通信

    我们知道 mutliprocessing 模块的 Queue 队列可以实现进程间通信,同样在线程间也可以使用 Queue 队列实现线程间通信。不同之处在于我们需要使用 queue 模块的 Queue 队列,而不是 multiprocessing 模块的 Queue 队列。但使用方法相同

    示例:

    from queue import Queue
    import random, threading, time
    
    # 生产者类
    class Producer(threading.Thread):
        def __init__(self, name, queue):
            threading.Thread.__init__(self, name=name)
            self.data = queue
        def run(self):
            for i in range(5):
                print("生产者 %s 将产品 %d 加入队列" % (self.getName(), i))
                self.data.put(i)
                time.sleep(random.random())
            print("生产者 %s 完成" % self.getName())
    
    # 消费者类
    class Consumer(threading.Thread):
        def __init__(self, name, queue):
            threading.Thread.__init__(self, name=name)
            self.data = queue
        def run(self):
            for i in range(5):
                val = self.data.get()
                print("消费者 %s 将产品 %d 从队列中取出" % (self.getName(), val))
                time.sleep(random.random())
            print("消费者 %s 完成" % self.getName())
    
    if __name__ == '__main__':
        print("---主线程开始---")
        queue = Queue()                         # 实例化队列
        producer = Producer("Producer", queue)  # 实例化线程 Producer,并传入队列作为参数
        consumer = Consumer("Consumer", queue)  # 实例化线程 Consumer,并传入队列作为参数
        producer.start()                        # 启动线程 Producer
        consumer.start()                        # 启动线程 Consumer
        producer.join()                         # 等待线程 Producer 结束
        consumer.join()                         # 等待线程 Consumer 结束
        print("---主线程结束---")
    

    上述例子的运行结果为:

    ---主线程开始---
    生产者 Producer 将产品 0 加入队列
    消费者 Consumer 将产品 0 从队列中取出
    生产者 Producer 将产品 1 加入队列
    消费者 Consumer 将产品 1 从队列中取出
    生产者 Producer 将产品 2 加入队列
    消费者 Consumer 将产品 2 从队列中取出
    生产者 Producer 将产品 3 加入队列
    生产者 Producer 将产品 4 加入队列
    消费者 Consumer 将产品 3 从队列中取出
    消费者 Consumer 将产品 4 从队列中取出
    生产者 Producer 完成
    消费者 Consumer 完成
    ---主线程结束---
    

    更多请参考

    展开全文
  • 彻底明白多线程通信机制

    千次阅读 2011-11-02 09:28:04
    线程间的通信 1. 线程的几种状态 线程有四种状态,任何一个线程肯定...2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表

     线程间的通信

    1.    线程的几种状态
    线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
    1)    产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
    2)    可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
    3)    死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。
    4)    停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程重新回到可执行状态时,它有可能重新执行。如通过对一个线程调用wait()函数后,线程就进入停滞状态,只有当两次对该线程调用notify或notifyAll后它才能两次回到可执行状态。
    2.    class Thread下的常用函数函数
    2.1    suspend()、resume()
    1)    通过suspend()函数,可使线程进入停滞状态。通过suspend()使线程进入停滞状态后,除非收到resume()消息,否则该线程不会变回可执行状态。
    2)    当调用suspend()函数后,线程不会释放它的“锁标志”。
    例11:
        class TestThreadMethod extends Thread{
            public static int shareVar = 0;
            public TestThreadMethod(String name){
                super(name);
            }
            public synchronized void run(){
                if(shareVar==0){
                    for(int i=0; i<5; i++){
                        shareVar++;
                        if(shareVar==5){
                            this.suspend(); //(1)
                        }
                    }
                }
                else{
                    System.out.print(Thread.currentThread().getName());
                    System.out.println(" shareVar = " + shareVar);
                    this.resume(); //(2)
                }
            }
        }
        public class TestThread{
            public static void main(String[] args){
                TestThreadMethod t1 = new TestThreadMethod("t1");
    TestThreadMethod t2 = new TestThreadMethod("t2");
    t1.start(); //(5)
                //t1.start(); //(3)
                t2.start(); //(4)
            }
    }
    运行结果为:
    t2 shareVar = 5
    i.    当代码(5)的t1所产生的线程运行到代码(1)处时,该线程进入停滞状态。然后排程器从线程池中唤起代码(4)的t2所产生的线程,此时shareVar值不为0,所以执行else中的语句。
    ii.    也许你会问,那执行代码(2)后为什么不会使t1进入可执行状态呢?正如前面所说,t1和t2是两个不同对象的线程,而代码(1)和(2)都只对当前对象进行操作,所以t1所产生的线程执行代码(1)的结果是对象t1的当前线程进入停滞状态;而t2所产生的线程执行代码(2)的结果是把对象t2中的所有处于停滞状态的线程调回到可执行状态。
    iii.    那现在把代码(4)注释掉,并去掉代码(3)的注释,是不是就能使t1重新回到可执行状态呢?运行结果是什么也不输出。为什么会这样呢?也许你会认为,当代码(5)所产生的线程执行到代码(1)时,它进入停滞状态;而代码(3)所产生的线程和代码(5)所产生的线程是属于同一个对象的,那么就当代码(3)所产生的线程执行到代码(2)时,就可使代码(5)所产生的线程执行回到可执行状态。但是要清楚,suspend()函数只是让当前线程进入停滞状态,但并不释放当前线程所获得的“锁标志”。所以当代码(5)所产生的线程进入停滞状态时,代码(3)所产生的线程仍不能启动,因为当前对象的“锁标志”仍被代码(5)所产生的线程占有。
    2.2     sleep()
    1)    sleep ()函数有一个参数,通过参数可使线程在指定的时间内进入停滞状态,当指定的时间过后,线程则自动进入可执行状态。
    2)    当调用sleep ()函数后,线程不会释放它的“锁标志”。
    例12:
        class TestThreadMethod extends Thread{
            class TestThreadMethod extends Thread{
            public static int shareVar = 0;
            public TestThreadMethod(String name){
                super(name);
            }
            public synchronized void run(){
                for(int i=0; i<3; i++){
                    System.out.print(Thread.currentThread().getName());
                    System.out.println(" : " + i);
                    try{
                        Thread.sleep(100); //(4)
                    }
                    catch(InterruptedException e){
                        System.out.println("Interrupted");
                    }
                }
            }
        }
        public class TestThread{
            public static void main(String[] args){
                TestThreadMethod t1 = new TestThreadMethod("t1");
                TestThreadMethod t2 = new TestThreadMethod("t2");
                t1.start(); (1)
                t1.start(); (2)
                //t2.start(); (3)
            }
    }
    运行结果为:
    t1 : 0
    t1 : 1
    t1 : 2
    t1 : 0
    t1 : 1
    t1 : 2
    由结果可证明,虽然在run()中执行了sleep(),但是它不会释放对象的“锁标志”,所以除非代码(1)的线程执行完run()函数并释放对象的“锁标志”,否则代码(2)的线程永远不会执行。
                    如果把代码(2)注释掉,并去掉代码(3)的注释,结果将变为:
    t1 : 0
    t2 : 0
    t1 : 1
    t2 : 1
    t1 : 2
    t2 : 2
    由于t1和t2是两个对象的线程,所以当线程t1通过sleep()进入停滞时,排程器会从线程池中调用其它的可执行线程,从而t2线程被启动。
                    例13:
        class TestThreadMethod extends Thread{
            public static int shareVar = 0;
            public TestThreadMethod(String name){
                super(name);
            }
            public synchronized void run(){
                for(int i=0; i<5; i++){
                    System.out.print(Thread.currentThread().getName());
                    System.out.println(" : " + i);
                    try{
                        if(Thread.currentThread().getName().equals("t1"))
                            Thread.sleep(200);
                        else
                            Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Interrupted");
                    }
                }
            }
        }
        public class TestThread{
            public static void main(String[] args){
                TestThreadMethod t1 = new TestThreadMethod("t1");
                TestThreadMethod t2 = new TestThreadMethod("t2");
                t1.start();
                //t1.start();
                t2.start();
            }
        }
    运行结果为:
    t1 : 0
    t2 : 0
    t2 : 1
    t1 : 1
    t2 : 2
    t2 : 3
    t1 : 2
    t2 : 4
    t1 : 3
    t1 : 4
    由于线程t1调用了sleep(200),而线程t2调用了sleep(100),所以线程t2处于停滞状态的时间是线程t1的一半,从从结果反映出来的就是线程t2打印两倍次线程t1才打印一次。
    2.3    yield()
    1)    通过yield ()函数,可使线程进入可执行状态,排程器从可执行状态的线程中重新进行排程。所以调用了yield()的函数也有可能马上被执行。
    2)    当调用yield ()函数后,线程不会释放它的“锁标志”。
    例14:
        class TestThreadMethod extends Thread{
            public static int shareVar = 0;
            public TestThreadMethod(String name){
                super(name);
            }
            public synchronized void run(){
                for(int i=0; i<4; i++){
                    System.out.print(Thread.currentThread().getName());
                    System.out.println(" : " + i);
                    Thread.yield();
                }
            }
        }
        public class TestThread{
            public static void main(String[] args){
                TestThreadMethod t1 = new TestThreadMethod("t1");
                TestThreadMethod t2 = new TestThreadMethod("t2");
                t1.start();
                t1.start(); //(1)
                //t2.start(); (2)
            }
    }
    运行结果为:
    t1 : 0
    t1 : 1
    t1 : 2
    t1 : 3
    t1 : 0
    t1 : 1
    t1 : 2
    t1 : 3
    从结果可知调用yield()时并不会释放对象的“锁标志”。
                    如果把代码(1)注释掉,并去掉代码(2)的注释,结果为:
    t1 : 0
    t1 : 1
    t2 : 0
    t1 : 2
    t2 : 1
    t1 : 3
    t2 : 2
    t2 : 3
    从结果可知,虽然t1线程调用了yield(),但它马上又被执行了。
    2.4    sleep()和yield()的区别
    1)    sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
    2)    sleep()可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。
    例15:
        class TestThreadMethod extends Thread{
            public static int shareVar = 0;
            public TestThreadMethod(String name){
                super(name);
            }
            public void run(){
                for(int i=0; i<4; i++){
                    System.out.print(Thread.currentThread().getName());
                    System.out.println(" : " + i);
                    //Thread.yield(); (1)
                    /* (2) */
                    try{
                        Thread.sleep(3000);
                    }
                    catch(InterruptedException e){
                        System.out.println("Interrupted");
                    }

                }
            }
        }
        public class TestThread{
            public static void main(String[] args){
                TestThreadMethod t1 = new TestThreadMethod("t1");
                TestThreadMethod t2 = new TestThreadMethod("t2");
                t1.setPriority(Thread.MAX_PRIORITY);
                t2.setPriority(Thread.MIN_PRIORITY);
                t1.start();
                t2.start();
            }
    }
    运行结果为:
    t1 : 0
    t1 : 1
    t2 : 0
    t1 : 2
    t2 : 1
    t1 : 3
    t2 : 2
    t2 : 3
    由结果可见,通过sleep()可使优先级较低的线程有执行的机会。注释掉代码(2),并去掉代码(1)的注释,结果为:
    t1 : 0
    t1 : 1
    t1 : 2
    t1 : 3
    t2 : 0
    t2 : 1
    t2 : 2
    t2 : 3
    可见,调用yield(),不同优先级的线程永远不会得到执行机会。
    2.5    join()
    使调用join()的线程执行完毕后才能执行其它线程,在一定意义上,它可以实现同步的功能。
    例16:
        class TestThreadMethod extends Thread{
            public static int shareVar = 0;
            public TestThreadMethod(String name){
                super(name);
            }
            public void run(){
                for(int i=0; i<4; i++){
                    System.out.println(" " + i);
                    try{
                        Thread.sleep(3000);
                    }
                    catch(InterruptedException e){
                        System.out.println("Interrupted");
                    }
                }
            }
        }
        public class TestThread{
            public static void main(String[] args){
                TestThreadMethod t1 = new TestThreadMethod("t1");
                t1.start();
                try{
                    t1.join();
                }
                catch(InterruptedException e){}
                t1.start();
            }
    }
    运行结果为:
     0
     1
     2
     3
     0
     1
     2
     3


    3. class Object下常用的线程函数
    wait()、notify()和notifyAll()这三个函数由java.lang.Object类提供,用于协调多个线程对共享数据的存取。
    3.1 wait()、notify()和notifyAll()
    1) wait()函数有两种形式:第一种形式接受一个毫秒值,用于在指定时间长度内暂停线程,使线程进入停滞状态。第二种形式为不带参数,代表waite()在notify()或notifyAll()之前会持续停滞。
    2) 当对一个对象执行notify()时,会从线程等待池中移走该任意一个线程,并把它放到锁标志等待池中;当对一个对象执行notifyAll()时,会从线程等待池中移走所有该对象的所有线程,并把它们放到锁标志等待池中。
    3) 当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
    例17:
    下面,我们将对例11中的例子进行修改
    class TestThreadMethod extends Thread{
    public static int shareVar = 0;
    public TestThreadMethod(String name){
    super(name);
    }
    public synchronized void run(){
    if(shareVar==0){
    for(int i=0; i<10; i++){
    shareVar++;
    if(shareVar==5){
    try{
    this.wait(); //(4)
    }
    catch(InterruptedException e){}
    }
    }
    }
    if(shareVar!=0){
    System.out.print(Thread.currentThread().getName());
    System.out.println(" shareVar = " + shareVar);
    this.notify(); //(5)
    }
    }
    }
    public class TestThread{
    public static void main(String[] args){
    TestThreadMethod t1 = new TestThreadMethod("t1");
    TestThreadMethod t2 = new TestThreadMethod("t2");
    t1.start(); //(1)
    //t1.start(); (2)
    t2.start(); //(3)
    }
    }
    运行结果为:
    t2 shareVar = 5
    因为t1和t2是两个不同对象,所以线程t2调用代码(5)不能唤起线程t1。如果去掉代码(2)的注释,并注释掉代码(3),结果为:
    t1 shareVar = 5
    t1 shareVar = 10
    这是因为,当代码(1)的线程执行到代码(4)时,它进入停滞状态,并释放对象的锁状态。接着,代码(2)的线程执行run(),由于此时shareVar值为5,所以执行打印语句并调用代码(5)使代码(1)的线程进入可执行状态,然后代码(2)的线程结束。当代码(1)的线程重新执行后,它接着执行for()循环一直到shareVar=10,然后打印shareVar。
    3.2 wait()、notify()和synchronized
    waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。
    例18:
    class TestThreadMethod extends Thread{
    public int shareVar = 0;
    public TestThreadMethod(String name){
    super(name);
    new Notifier(this);
    }
    public synchronized void run(){
    if(shareVar==0){
    for(int i=0; i<5; i++){
    shareVar++;
    System.out.println("i = " + shareVar);
    try{
    System.out.println("wait......");
    this.wait();
    }
    catch(InterruptedException e){}
    }
    }
    }
    }
    class Notifier extends Thread{
    private TestThreadMethod ttm;
    Notifier(TestThreadMethod t){
    ttm = t;
    start();
    }
    public void run(){
    while(true){
    try{
    sleep(2000);
    }
    catch(InterruptedException e){}
    /*1 要同步的不是当前对象的做法 */
    synchronized(ttm){
    System.out.println("notify......");
    ttm.notify();
    }
    }
    }
    }
    public class TestThread{
    public static void main(String[] args){
    TestThreadMethod t1 = new TestThreadMethod("t1");
    t1.start();
    }
    }
    运行结果为:
    i = 1
    wait......
    notify......
    i = 2
    wait......
    notify......
    i = 3
    wait......
    notify......
    i = 4
    wait......
    notify......
    i = 5
    wait......
    notify......
    4. wait()、notify()、notifyAll()和suspend()、resume()、sleep()的讨论
    4.1 这两组函数的区别
    1) wait()使当前线程进入停滞状态时,还会释放当前线程所占有的“锁标志”,从而使线程对象中的synchronized资源可被对象中别的线程使用;而suspend()和sleep()使当前线程进入停滞状态时不会释放当前线程所占有的“锁标志”。
    2) 前一组函数必须在synchronized函数或synchronized block中调用,否则在运行时会产生错误;而后一组函数可以non-synchronized函数和synchronized block中调用。
    4.2 这两组函数的取舍
    Java2已不建议使用后一组函数。因为在调用wait()时不会释放当前线程所取得的“锁标志”,这样很容易造成“死锁”

    展开全文
  • 多核多线程处理器[1]是并行技术的一个发展方向,基于多核多线程处理器,提出了一种时钟共享多线程处理器。该处理器有近邻通信和线程间通信两种通信机制,近邻通信采用近邻共享FIFO来传递信息,线程间通信通过线程间...
  • java多线程通信图解

    2017-11-29 20:03:50
    一张图方便理解和掌握java 多线程之间通信的实质 java 多线程 其实就是每个线程都拥有自己的内存空间,多线程之间的通信,比例A线程修改了主内存(main方法的线程)变量,需要把A线程修改的结果同步到主线程中,...
  • Java中的多线程(线程间通信

    万次阅读 多人点赞 2018-09-23 10:22:42
    线程通信: /学习笔记/ 线程在处理同一资源,但是任务却不同。 先看一个例子,采用两个线程执行进行输入和输出任务: //资源 class Resource { String name; String sex; } //输入 ...

    /学习笔记/

    线程间通信:

    多个线程在处理同一资源,但是任务却不同。
    先看一个例子,采用两个线程执行进行输入和输出任务:

          //资源
            class Resource
            {
            	String name;
            	String sex;
            }
        
        
        //输入
        class Input implements Runnable
        {
        	Resource r ;
        //	Object obj = new Object();
        	Input(Resource r)
        	{
        		this.r = r;
        	}
        	public void run()
        	{
        		int x = 0;
        		while(true)
        		{
        	
        				if(x==0)
        				{
        					r.name = "mike";
        					r.sex = "nan";
        				}
        				else
        				{
        					r.name = "丽丽";
        					r.sex = "女女女女女女";
        				}
    
        			x = (x+1)%2;
        
        		}
        	}
        }
        //输出
        class Output implements Runnable
        {
        
        	Resource r;
    
        	Output(Resource r)
        	{
        		this.r = r;
        	}
        
        	public void run()
        	{
        		while(true)
        		{
        		
    
        				System.out.println(r.name+"....."+r.sex);
    
        		}
        	}
        }
        
        
        
        class  ResourceDemo
        {
        	public static void main(String[] args) 
        	{
        		//创建资源。
        		Resource r = new Resource();
        		//创建任务。
        		Input in = new Input(r);
        		Output out = new Output(r);
        		//创建线程,执行路径。
        		Thread t1 = new Thread(in);
        		Thread t2 = new Thread(out);
        		//开启线程
        		t1.start();
        		t2.start();
        	}
        }
    

    运行结果如下图所示,产生了多线程的安全问题,因为有多个线程在操作同一个共享数据(name,sex)。当输入方法还未执行完毕,输出方法就抢先将还未赋值正确的(name,sex)进行输出了。
    在这里插入图片描述
    改进办法:加入同步锁(监视器)
    在这里插入图片描述
    在这里插入图片描述
    由于使用的都是r对象这同一个锁,可以保证输入方法执行完毕之后,另一个线程再执行输出方法。
    在这里插入图片描述
    上图中,输出方法拿到执行权后进行了反复输出,能否做到只输出一次,就让输入方法进行修改的效果呢?下面的机制可以解决。

    等待/唤醒机制

    1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
    如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。

    2,notify():唤醒线程池中一个线程(任意)。如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。

    3,notifyAll():唤醒线程池中的所有线程。如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

    这些方法都必须定义在同步中。
    因为这些方法是用于操作线程状态的方法。
    必须要明确到底操作的是哪个锁上的线程。

    使用wait方法和使用synchornized来分配cpu时间是有本质区别的。wait会释放锁,synchornized不释放锁。

    以下例子对上面的代码进行了优化,使用wait方法和notify方法,使两个线程交替进行。

        class Resource
        {
        	private String name;
        	private String sex;
        	private boolean flag = false;
        
        	public synchronized void set(String name,String sex)
        	{
        		if(flag)
        			try{this.wait();}catch(InterruptedException e){}  //同步函数的锁是this
        		this.name = name;
        		this.sex = sex;
        		flag = true;
        		this.notify();
        	}
        
        	public synchronized void out()
        	{
        		if(!flag)
        			try{this.wait();}catch(InterruptedException e){}
        		System.out.println(name+"...+...."+sex);
        		flag = false;
        		notify();
        	}
        }
        
        
        //输入
        class Input implements Runnable
        {
        	Resource r ;
    
        	Input(Resource r)
        	{
        		this.r = r;
        	}
        	public void run()
        	{
        		int x = 0;
        		while(true)
        		{
        			if(x==0)
        			{
        				r.set("mike","nan");
        			}
        			else
        			{
        				r.set("丽丽","女女女女女女");
        			}
        			x = (x+1)%2;
        		}
        	}
        }
        //输出
        class Output implements Runnable
        {
        
        	Resource r;
    
        	Output(Resource r)
        	{
        		this.r = r;
        	}
        
        	public void run()
        	{
        		while(true)
        		{
        			r.out();
        		}
        	}
        }
        
        
        
        class  ResourceDemo3
        {
        	public static void main(String[] args) 
        	{
        		//创建资源。
        		Resource r = new Resource();
        		//创建任务。
        		Input in = new Input(r);
        		Output out = new Output(r);
        		//创建线程,执行路径。
        		Thread t1 = new Thread(in);
        		Thread t2 = new Thread(out);
        		//开启线程
        		t1.start();
        		t2.start();
        	}
        }
    

    在这里插入图片描述

    多生产者+多消费者问题

    这是一个经典例子,代码如下:

        class Resource
        {
        	private String name;
        	private int count = 1;
        	private boolean flag = false;
        	public synchronized void set(String name)//  t0   t1
        	{
        		while(flag)
        			try{this.wait();}catch(InterruptedException e){} //若线程在此处被唤醒,需要回头重新判断标记
        		
        		this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
        		count++;//2 3 4
        		System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
        		flag = true;
        		notify();
        	}
        
        	public synchronized void out()
        	{
        		while(!flag)
        			try{this.wait();}catch(InterruptedException e){}	//t2  t3
        		System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
        		flag = false;
        		notify();
        	}
        }
        
        class Producer implements Runnable
        {
        	private Resource r;
        	Producer(Resource r)
        	{
        		this.r = r;
        	}
        	public void run()
        	{
        		while(true)
        		{
        			r.set("烤鸭");
        		}
        	}
        }
        
        class Consumer implements Runnable
        {
        	private Resource r;
        	Consumer(Resource r)
        	{
        		this.r = r;
        	}
        	public void run()
        	{
        		while(true)
        		{
        			r.out();
        		}
        	}
        }
        
        
        
        class  ProducerConsumerDemo
        {
        	public static void main(String[] args) 
        	{
        		Resource r = new Resource();
        		Producer pro = new Producer(r);
        		Consumer con = new Consumer(r);
        
        		Thread t0 = new Thread(pro);
        		Thread t1 = new Thread(pro);
        		Thread t2 = new Thread(con);
        		Thread t3 = new Thread(con);
        		t0.start();
        		t1.start();
        		t2.start();
        		t3.start();
        
        	}
        }
    

    while判断标记,解决了线程获取执行权后,是否要运行的判断问题
    notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁(如下图)。因为所有线程都被冻结无人唤醒。
    在这里插入图片描述

    notifyAll达到了这样的效果:本方线程一定会唤醒对方线程。
    ——小结:while+notifyAll可以解决此类问题。
    那么问题来了,能否有更好的方法呢?

    接口 Lock

    jdk1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。
    以下引用自API文档:

    Lock 实现提供了比使用 synchronized方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

    锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。不过,某些锁可能允许对共享资源并发访问, ReadWriteLock 的读取锁。

    synchronized方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。

    虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用
    “hand-over-hand” 或 “chain locking”:获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。

    Lock接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。

    随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:

         Lock l = ...; 
         l.lock();
         try {
             // access the resource protected by this lock
         } finally {
             l.unlock();
         }
    

    Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。
    同时更为灵活。可以一个锁上加上多组监视器。
    lock():获取锁。
    unlock():释放锁,通常需要定义finally代码块中。

    Condition接口:出现替代了Object中的wait notify notifyAll方法。
    将这些监视器方法单独进行了封装,变成Condition监视器对象。
    可以任意锁进行组合。
    await();
    signal();
    signalAll();
    将其应用到上面提到的生产者消费者问题中:

        import java.util.concurrent.locks.*;
    
        class Resource
        {
        	private String name;
        	private int count = 1;
        	private boolean flag = false;
        
        //	创建一个锁对象。
        	Lock lock = new ReentrantLock();
        
        	//通过已有的锁获取该锁上的监视器对象。
        //	Condition con = lock.newCondition();
        
        	//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
        	Condition producer_con = lock.newCondition();
        	Condition consumer_con = lock.newCondition();
        
        	
        	public  void set(String name)//  t0 t1
        	{
        		lock.lock();
        		try
        		{
        			while(flag)
        //			try{lock.wait();}catch(InterruptedException e){}//   对比,这是之前的写法
        			try{producer_con.await();}catch(InterruptedException e){}
        		
        			this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
        			count++;//2 3 4
        			System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
        			flag = true;
    
        			consumer_con.signal(); //唤醒对方线程
        		}
        		finally
        		{
        			lock.unlock(); //释放锁
        		}
        		
        	}
        
        	public  void out()// t2 t3
        	{
        		lock.lock();
        		try
        		{
        			while(!flag)
        //			try{this.wait();}catch(InterruptedException e){}	//t2  t3
        			try{cousumer_con.await();}catch(InterruptedException e){}	//t2  t3
        			System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
        			flag = false;
    
        			producer_con.signal();
        		}
        		finally
        		{
        			lock.unlock();
        		}
        		
        	}
        }
        
        class Producer implements Runnable
        {
        	private Resource r;
        	Producer(Resource r)
        	{
        		this.r = r;
        	}
        	public void run()
        	{
        		while(true)
        		{
        			r.set("烤鸭");
        		}
        	}
        }
        
        class Consumer implements Runnable
        {
        	private Resource r;
        	Consumer(Resource r)
        	{
        		this.r = r;
        	}
        	public void run()
        	{
        		while(true)
        		{
        			r.out();
        		}
        	}
        }
        
        
        
        class  ProducerConsumerDemo2
        {
        	public static void main(String[] args) 
        	{
        		Resource r = new Resource();
        		Producer pro = new Producer(r);
        		Consumer con = new Consumer(r);
        
        		Thread t0 = new Thread(pro);
        		Thread t1 = new Thread(pro);
        		Thread t2 = new Thread(con);
        		Thread t3 = new Thread(con);
        		t0.start();
        		t1.start();
        		t2.start();
        		t3.start();
        
        	}
        }
    

    wait 和 sleep 的区别

    1,wait可以指定时间也可以不指定。
    sleep必须指定时间。

    2,在同步中时,对cpu的执行权和锁的处理不同。
    wait:释放执行权,释放锁。
    sleep:释放执行权,不释放锁。

    停止线程

    停止线程:
    1,stop方法。

    2,run方法结束。

    怎么控制线程的任务结束呢?
    任务中都会有循环结构,只要控制住循环就可以结束任务。
    控制循环通常就用定义标记来完成。

    但是如果线程处于了冻结状态,无法读取标记。如何结束呢?
    可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。
    但是强制动作会发生了InterruptedException,记得要处理。

    线程类的其他方法

    守护线程:setDaemon(boolean on)
    将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
    该方法必须在启动线程前调用。
    join

        public final void join()
                        throws InterruptedException
    

    等待当前线程终止(就加入)。 临时加入一个线程运算时可以使用join方法。

    多线程总结

    1,进程和线程的概念。
    |–进程:
    |–线程:

    2,jvm中的多线程体现。
    |–主线程,垃圾回收线程,自定义线程。以及他们运行的代码的位置。

    3,什么时候使用多线程,多线程的好处是什么?创建线程的目的?
    |–当需要多部分代码同时执行的时候,可以使用。

    4,创建线程的两种方式。★★★★★
    |–继承Thread
    |–步骤
    |–实现Runnable
    |–步骤
    |–两种方式的区别?

    5,线程的5种状态。
    对于执行资格和执行权在状态中的具体特点。
    |–被创建:
    |–运行:
    |–冻结:
    |–临时阻塞:
    |–消亡:

    6,线程的安全问题。★★★★★
    |–安全问题的原因:
    |–解决的思想:
    |–解决的体现:synchronized
    |–同步的前提:但是加上同步还出现安全问题,就需要用前提来思考。
    |–同步的两种表现方法和区别:
    |–同步的好处和弊端:
    |–单例的懒汉式。
    |–死锁。

    7,线程间的通信。等待/唤醒机制。
    |–概念:多个线程,不同任务,处理同一资源。
    |–等待唤醒机制。使用了锁上的 wait notify notifyAll. ★★★★★
    |–生产者/消费者的问题。并多生产和多消费的问题。 while判断标记。用notifyAll唤醒对方。 ★★★★★
    |–JDK1.5以后出现了更好的方案,★★★
    Lock接口替代了synchronized
    Condition接口替代了Object中的监视方法,并将监视器方法封装成了Condition
    和以前不同的是,以前一个锁上只能有一组监视器方法。现在,一个Lock锁上可以多组监视器方法对象。
    可以实现一组负责生产者,一组负责消费者。
    |–wait和sleep的区别。★★★★★

    8,停止线程的方式。
    |–原理:
    |–表现:–中断。

    9,线程常见的一些方法。
    |–setDaemon()
    |–join();
    |–优先级
    |–yield();
    |–在开发时,可以使用匿名内部类来完成局部的路径开辟。

    展开全文
  • 时钟共享多线程处理器通信机制的设计与实现.pdf
  • 主要介绍了Java多线程线程通信生产者消费者模式及等待唤醒机制代码详解,具有一定参考价值,需要的朋友可以了解下。
  • 支持多线程并发与消息异步处理的Linux Netlink通信机制研究.pdf
  • Java多线程通信机制

    千次阅读 2012-12-26 16:54:34
    Java提供了3个非常重要的方法来巧妙地解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。它们都是Object类的最终方法,因此每一个类都默认拥有它们。  虽然所有的类都默认拥有这3个方法,...
  • 多线程编程及线程间通信机制

    千次阅读 2015-04-05 15:22:34
    最好的办法自然是练习再练习,然后还要看很的代码才是,之前又听说了一个IT同行过劳死,特别的提醒广大的IT从业者,要注意合理的作息习惯,健康才是最重要的,下面结合网上的一些文章,对线程进行详细的剖析 ...
  • 文档详细介绍了Handler实现线程通信过程中源码的实现机制,并对其中的Looper,MessageQueue,Message对象的初始化及sendMessage()通过sendMessageDelayed()和sendMessageAtTime()过程的操作机流程
  • 本文以退火炉温度控制系统为例,介绍了在Windows XP下利用Delphi7.0多线程机制实现微机与OMRON C200HG之间的上位机链接通信,详细论述了硬件配置,PLC通信协议,程序编写。充分使用了多线程机制通信程序条理清楚,...
  • 线程通信机制wait notify notifyAll 本课时我们主要学习 wait/notify/notifyAll 方法的使用注意事项。 我们主要从三个问题入手: 为什么 wait 方法必须在 synchronized 保护的同步代码中使用? 为什么 wait/notify/...
  • python的多线程及线程间的通信方式

    千次阅读 2020-11-04 22:56:15
    而一个进程中有可以同时拥有多个线程执行,这种情况就被称为多线程。 并发与并行: 线程的并发是指处理器CPU在极短的时间内交替执行每个线程,而并行是指CPU同时处理多个线程。 2. 创建线程的方法 在python中,创建...
  • 线程通信机制

    千次阅读 2018-09-24 16:23:47
    一 java实现线程通信机制主要通过以下几种方式 1 while()轮询 2 等待/通知机制 wait()、notify()、notifyAll()结合synchronized关键字 3 条件对象:Condition Condition和ReentrantLock重入锁     此外,...
  • 线程通信  线程线程之间不是独立的个体,它们彼此之间可以相互通信与协作。  线程通信后,系统之间的交互性会更强大,在大大提交CPU利用率的同时,还会使程序要对各线程任务在处理的过程中进行有效的把控...
  • 多线程机制

    2012-09-19 16:46:47
    多线程机制 1 1、 Runnable接口与Thread类 1 2、 两个创建线程方法的比较 3 3、 几个常用的改变线程状态的方法 3 4、 线程的同步机制 8 5、 死锁 11 6、 线程间通信,也叫生产者与消费者问题 15 7、 浅析 Java ...
  • 多线程-线程之间的通信

    千次阅读 2020-10-17 22:41:13
    线程通信就是当个线程共同操作共享的资源时,互相告知自己的状态以避免资源争夺。 2、线程通信的方式 线程通信主要可以分为三种方式,分别为共享内存、消息传递和管道流。每种方式有不同的方法来实现。 共享内存...
  • 本文从实战、原理以及性能优化三个方面,详细且全面的介绍了Hander通信机制的使用、低层原理的实现,以及Handler内存泄漏的原因及解决方案的实现。
  • Qt多线程通信

    万次阅读 多人点赞 2018-03-03 11:56:03
    简述: 1> Qt线程间共享数据主要有两种方式: ...2)使用singal/slot机制,把数据从一个线程传递到另外一个线程。 第一种方法在各个编程语言都普遍使用,而第二种方法是QT的特有的,本文主要介绍第二种。 2 >
  • Windows下基于socket多线程并发通信的实现

    千次下载 热门讨论 2015-04-07 15:06:06
    本文介绍了在Windows 操作系统下基于TCP/IP 协议Socket 套接口的通信机制以及多线程编程知识与技巧,并给出多线程方式实现多用户与服务端(C/S)并发通信模型的详细算法,最后展现了用C++编写的多用户与服务器通信的...
  • 学习线程之间的通信协调关系。 2. 使用 runnable 接口实现按两个不同的时间间隔( 1 秒和 3 秒)在屏幕上显示当前时间。 3.写一个程序,模拟4个售票窗口共同卖100张火车票的程序。 使用继承Thread类方式和实现...
  • Java多线程编程-(4)-线程间通信机制的介绍与使用

    千次阅读 多人点赞 2017-10-10 18:25:52
    上一篇:Java多线程编程-(1)-线程安全和锁Synchronized概念Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性Java多线程编程-(3)-线程本地ThreadLocal的介绍与使用线程间通信简介我们知道线程是操作...
  • Androi多线程通信 - Handler机制 Android的主线程不能进行耗时操作,耗时操作放在子线程执行 在子线程中只能进行一些耗时的操作,而不能直接操纵UI,只能由主线程操作。 Handler异步通信系统 handler是Android给...
  • 多进程和多线程是系统执行多任务机制的重要手段,多任务同时进行自然少不了相互之间的通信工作。下面先将线程间的通信方式总结一下,便于大家对比学习。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 273,135
精华内容 109,254
关键字:

多线程通信机制

友情链接: Retinex.zip