精华内容
下载资源
问答
  • java线程通信

    2014-11-06 22:16:26
    线程通信,这里主要是线程的一些问题,用来对初学者来说看看还是不错的
  • Java线程通信

    万次阅读 2019-08-21 23:26:20
    其实把ABC当做线程,这便是一个线程通信的例子。 wait(); 使执行的线程进行等待 notify(); 使停止的线程继续运行, join(); 使所属线程正常执行run方法,而当前线程暂时阻塞,有排队的作用 notify与no...

    我先提出一个例子
    A,B为一组,A走1米,然后 B走一米,总共100米(就是A,B轮流输出100个数)
    其实把AB当做线程,这便是一个线程通信的例子。

    wait(); 使执行的线程进行等待
    notify(); 使停止的线程继续运行,
    join(); 使所属线程正常执行run方法,而当前线程暂时阻塞,有排队的作用
    notify与notifyAll的区别
    notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者,以判断程序是否可以继续往下执行。
    线程通信主要靠的是这3个函数,但是本次例子中只使用了前2个函数,join将单独讲解。
    先看看本次例子代码如何写的

    public class C{       //记录距离
    	  int i=100;
    	  boolean flag = false; //两个线程,交替执行的一个标志
    }
    
    
    public class A implements Runnable{
    	private C c;
    	public A(C c) {
       this.c=c;
    	}
    		@Override
    		public void run() {
    		while(c.i>0) {
    			synchronized (c) {              //必须要用一把锁对象,这个对象是c
    				if(c.flag) {
    					try {
    						c.wait();           //操作wait()函数的必须和锁是同一个
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}
         else {
    		    c.i--;
    		    System.out.println("A跑完了,还剩下"+c.i+"米");	
    		    c.flag=true;
    		    c.notify();
         }							
    			}		
    		}	
      }
    }
    
    
    public class B implements Runnable{
    	private C c;
    
    	public B(C c) {
       this.c=c;
    	}
    		@Override
    		public void run() {
    		while(c.i>0) {
    			synchronized (c) {
    				if(!c.flag) {
    					try {
    						c.wait();
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    				}
         else {
    		    c.i--;
    		    System.out.println("B跑完了,还剩下"+c.i+"米");	
    		    c.flag=false;
    		    c.notify();
         }							
    			}		
    		}	
      }
    }
    
    public class Main {
    
    public static void main(String[] args) throws InterruptedException {
    C c=new C();
    A a=new A(c);
    B b=new B(c);
    Thread a1=new Thread(a);
    Thread b1=new Thread(b);
    a1.start();
    b1.start();
                                      
    	}
    }
    
    

    在这里插入图片描述
    首先我们通过锁(也必须有锁)保证了他们只有一个执行,然后通过一个执行一个停止的机制保证了他们的轮换。
    这个问题其实在线程通信中属于基础但不简单的,明白了其中的原理,在去搞其他线程通信就会容易很多的。

    展开全文
  • Java线程通信详解

    2020-09-01 08:37:44
    本篇文章主要介绍了Java线程通信问题,线程通信用来保证线程协调运行,有需要的朋友可以了解一下。
  • 主要介绍了Java 线程通信的的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
  • 主要介绍了JAVA 线程通信相关知识,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
  • Java 线程通信示例 源代码 多线程之间通信,值得收藏
  • 深入理解java线程通信

    2020-08-25 23:54:13
    开发中不免会遇到需要所有子线程执行完毕通知主线程处理某些逻辑的场景。或者是线程 A 在执行到某个条件通知线程 B 执行某个操作。下面我们来一起学习如何解决吧
  • java线程通信---pipe管道

    千次阅读 2017-02-05 11:18:40
    java线程通信,pipe管道

    java线程之间的通信方式也比较多,这里总结一下自己理解的pipe管道通信。

    一、建立管道输入端和输出端的连接
    首先为了创建一个管道流,我们必须首先创建一个PipedOutputStream对象,然后创建一个PipedInputStream对象。如下:
    PipedOutputStream out = null;
    PipedInputStream in = null;
    对象建立好以后使用connect()方法将二者建立连接
    out.connect(in);
    该方法在PipedOutputStream 、PipedInputStream当中都有,随便调用那个来建立连接都可以,但注意智能建立一次连接,重复建立会抛异常。
    不使用connect()方法也是可以建立连接的,方法如下:
    out = new PipedOutputStream(in );
    一旦建立了管道,就可以像操作文件一样对管道进行数据读写。

    二、开始通信
    首先有一点特别注意,不能在同一个线程当中既写入又读取,这样会造成死锁,因为管道会有阻塞的时候(当管道当中没有数据,进行读操作时,读操作的线程会阻塞,直到有线程来写数据;当管道当中满数据,进行写操作时,写操作的线程阻塞,直到有线程来读数据),有时需要写和读的两端同时都在工作,只有一个线程去完成读和写,显然无法保证能够同时读写,所以读写最好放在单独的线程去完成。
    建立的管道是一个包含1024字节大小的循环缓冲数组,从管道当中读取的数据,会被清除出管道,即是读取以后就相当于把该数据从管道当中拿走了,所以是循环缓冲数组。
    下面演示代码:

    package cn.zhoucy.pipe;
    import java.io.IOException;
    import java.io.PipedInputStream;
    import java.io.PipedOutputStream;
    
    public class TestPiped {
    
    public static void main(String[] args) {
    
        Sender sender = new Sender();
        Recive recive = new Recive();
        PipedInputStream pi = recive.getPipedInputputStream();
        PipedOutputStream po = sender.getPipedOutputStream();
        try {
            pi.connect(po);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        new Thread(sender).start();
        new Thread(recive).start();
    
    }
    }
    
    class Sender implements Runnable {
    PipedOutputStream out = null;
    
    public PipedOutputStream getPipedOutputStream() {
        out = new PipedOutputStream();
        return out;
    }
    
    @Override
    public void run() {
    
        try {
            out.write("Hello , Reciver!".getBytes());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        try {
            out.close();
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    
    }
    
    }
    
    class Recive implements Runnable {
    PipedInputStream in = null;
    
    public PipedInputStream getPipedInputputStream() {
        in = new PipedInputStream();
        return in;
    }
    
    @Override
    public void run() {
    
        byte[] bys = new byte[1024];
        try {
            in.read(bys);
            System.out.println("读取到的信息:" + new String(bys).trim());
            in.close();
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    
        }
    }
    

    运行结果如下:

    这里写图片描述

    参考文章:
    http://blog.csdn.net/zlp1992/article/details/50298195#comments
    http://www.cnblogs.com/songxingzhu/archive/2012/09/17/2688969.html

    展开全文
  • java线程通信课程设计

    2011-05-01 20:22:17
    线程通信,采用java技术,实现线程之间的通信。
  • JAVA线程通信详解

    万次阅读 多人点赞 2018-10-14 09:11:36
     线程线程之间不是相互独立的个体,它们彼此之间需要相互通信和协作,最典型的例子就是生产者-消费者问题:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对...

    目录

    一、概述

    二、wait/notify 机制

    三、Condition

    四、生产者/消费者模式

    五、线程间的通信——管道

    六、方法Join的使用


    一、概述

           线程与线程之间不是相互独立的个体,它们彼此之间需要相互通信和协作,最典型的例子就是生产者-消费者问题:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权。因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去。因此一般情况下,当队列满时,会让生产者交出对临界资源的占用权,并进入挂起状态。然后等待消费者消费了商品,然后消费者通知生产者队列有空间了。同样地,当队列空时,消费者也必须等待,等待生产者通知它队列中有商品了。这种互相通信的过程就是线程间的协作。本文首先介绍 wait/notify 机制,并对实现该机制的两种方式——synchronized+wait-notify模式和Lock+Condition模式进行详细剖析,以作为线程间通信与协作的基础。进一步地,以经典的生产者-消费者问题为背景,熟练对 wait/notify 机制的使用。最后对 Thread 类中的 join() 方法进行源码分析,并以宿主线程与寄生线程的协作为例进行说明。在下面的例子中,虽然两个线程实现了通信,但是凭借线程B不断地通过while语句轮询来检测某一个条件,这样会导致CPU的浪费。因此,需要一种机制来减少CPU资源的浪费,而且还能实现多个线程之间的通信,即 wait/notify 机制。

    //资源类
    class MyList {
    
        //临界资源
        private volatile List<String> list = new ArrayList<String>();
    
        public void add() {
            list.add("abc");
        }
    
        public int size() {
            return list.size();
        }
    }
    
    // 线程A
    class ThreadA extends Thread {
    
        private MyList list;
    
        public ThreadA(MyList list,String name) {
            super(name);
            this.list = list;
        }
    
        @Override
        public void run() {
            try {
                for (int i = 0; i < 3; i++) {
                    list.add();
                    System.out.println("添加了" + (i + 1) + "个元素");
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    //线程B
    class ThreadB extends Thread {
    
        private MyList list;
    
        public ThreadB(MyList list,String name) {
            super(name);
            this.list = list;
        }
    
        @Override
        public void run() {
            try {
                while (true) {          // while 语句轮询
                    if (list.size() == 2) {
                        System.out.println("==2了,线程b要退出了!");
                        throw new InterruptedException();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    //测试
    public class Test {
        public static void main(String[] args) {
    
            MyList service = new MyList();
    
            ThreadA a = new ThreadA(service,"A");
            ThreadB b = new ThreadB(service,"B");
    
            a.start();
            b.start();
        }
    }
    /* Output(输出结果不唯一): 
       添加了1个元素
       添加了2个元素
       ==2了,线程b要退出了!
       java.lang.InterruptedException at test.ThreadB.run(Test.java:57)
       添加了3个元素
     */

    二、wait/notify 机制

           在这之前,线程间通过共享数据来实现通信,即多个线程主动地读取一个共享数据,通过 同步互斥访问机制保证线程的安全性。等待/通知机制主要由Object类中的wait()、notify() 和 notifyAll()三个方法来实现,这三个方法均非Thread类中所声明的方法,而是Object类中声明的方法。原因是每个对象都拥有monitor(锁),所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作,而不是用当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。

    1.wait()——让当前线程 (Thread.concurrentThread() 方法所返回的线程) 释放对象锁并进入等待(阻塞)状态。

    • 方法声明:public final native void wait(long timeout) throws InterruptedException;
    • 方法作用:Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on this object’s monitor by calling one of the wait() methods.This method causes the current thread (call it T):① to place itself in the wait set for this object;② to relinquish (放弃) any and all synchronization claims on this object;③ Thread T becomes disabled for thread scheduling purposes and lies dormant (休眠) until one of four things happens:Some other thread invokes the notify method for this object and thread T happens to be arbitrarily chosen as the thread to be awakened;Some other thread invokes the notifyAll method for this object;Some other thread interrupts thread T;The specified amount of real time has elapsed, more or less. If timeout is zero, however, then real time is not taken into consideration and the thread simply waits until notified (等待时间为 0 意味着永远等待,直至线程被唤醒) .The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It then competes in the usual manner with other threads for the right to synchronize on the object; once it has gained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.
    • 方法使用条件:This method should only be called by a thread that is the owner of this object’s monitor.
    • 异常:运行时(不受检查)异常 IllegalMonitorStateException: if the current thread is not the owner of this object’s monitor; IllegalArgumentException: if the value of timeout is negative;受检查异常 (中断阻塞线程,抛 InterruptedException并终止线程,释放锁,释放CPU) InterruptedException: if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.

    2.notify()——唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到CPU的执行。

    • 方法声明:public final native void notify();
    • 方法作用:Wakes up a single thread that is waiting on this object’s monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation.The awakened thread will not be able to proceed until the current thread relinquishes (放弃) the lock on this object.(在执行 notify() 方法后,当前线程不会马上释放该锁对象,呈 wait 状态的线程也并不能马上获取该对象锁。只有等到执行notify()方法的线程退出synchronized代码块/方法后,当前线程才会释放锁,而相应的呈wait状态的线程才可以去争取该对象锁。) The awakened thread will compete in the usual manner with any other threads that might be actively competing to (竞争) synchronize on this object; the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
    • 方法使用条件This method should only be called by a thread that is the owner of this object’s monitor. A thread becomes the owner of the object’s monitor in one of three ways:By executing a synchronized instance method of that object;By executing the body of a synchronized statement that synchronizes on the object;For objects of type Class, by executing a synchronized static method of that class.Only one thread at a time can own an object’s monitor(互斥锁).
    • 异常:运行时(不受检查)异常 IllegalMonitorStateException: if the current thread is not the owner of this object’s monitor.

    3.notifyAll()——唤醒所有正在等待相应对象锁的线程,使它们进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到CPU的执行。

    • 方法声明:public final native void notifyAll();
    • 方法作用:Wakes up all threads that are waiting on this object’s monitor. A thread waits on an object’s monitor by calling one of the wait methods.The awakened threads will not be able to proceed until the current thread relinquishes (放弃) the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to (竞争) synchronize on this object; the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
    • 方法使用条件:This method should only be called by a thread that is the owner of this object’s monitor.
    • 异常:运行时(不受检查)异常 IllegalMonitorStateException: if the current thread is not the owner of this object’s monitor.

    4.小结

            从以上描述可以得出:wait()、notify() 和 notifyAll()方法是 本地方法,并且为 final 方法,无法被重写;调用某个对象的 wait() 方法能让 当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁);调用某个对象的 notify() 方法能够唤醒 一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程。

    • 方法调用与线程状态关系

      每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了已就绪(将要竞争锁)的线程,阻塞队列存储了被阻塞的线程。当一个阻塞线程被唤醒后,才会进入就绪队列,进而等待CPU的调度;反之,当一个线程被wait后,就会进入阻塞队列,等待被唤醒。

    Threadæ¹æ³ä¸ç¶æ.jpg-73.5kB       

    • 使用举例
    public class Test {
        public static Object object = new Object();
    
        public static void main(String[] args) throws InterruptedException {
            Thread1 thread1 = new Thread1();
            Thread2 thread2 = new Thread2();
    
            thread1.start();
    
            Thread.sleep(2000);
    
            thread2.start();
        }
    
        static class Thread1 extends Thread {
            @Override
            public void run() {
                synchronized (object) {
                    System.out.println("线程" + Thread.currentThread().getName()
                            + "获取到了锁...");
                    try {
                        System.out.println("线程" + Thread.currentThread().getName()
                                + "阻塞并释放锁...");
                        object.wait();
                    } catch (InterruptedException e) {
                    }
                    System.out.println("线程" + Thread.currentThread().getName()
                            + "执行完成...");
                }
            }
        }
    
        static class Thread2 extends Thread {
            @Override
            public void run() {
                synchronized (object) {
                    System.out.println("线程" + Thread.currentThread().getName()
                            + "获取到了锁...");
                    object.notify();
                    System.out.println("线程" + Thread.currentThread().getName()
                            + "唤醒了正在wait的线程...");
                }
                System.out
                        .println("线程" + Thread.currentThread().getName() + "执行完成...");
            }
        }
    }
    /* Output: 
            线程Thread-0获取到了锁...
            线程Thread-0阻塞并释放锁...
            线程Thread-1获取到了锁...
            线程Thread-1唤醒了正在wait的线程...
            线程Thread-1执行完成...
            线程Thread-0执行完成...
     */
    • 多个同类型线程的场景(wait 的条件发生变化)
    //资源类
    class ValueObject {
        public static List<String> list = new ArrayList<String>();
    }
    
    //元素添加线程
    class ThreadAdd extends Thread {
    
        private String lock;
    
        public ThreadAdd(String lock,String name) {
            super(name);
            this.lock = lock;
        }
    
        @Override
        public void run() {
            synchronized (lock) {
                ValueObject.list.add("anyString");
                lock.notifyAll();               // 唤醒所有 wait 线程
            }
        }
    }
    
    //元素删除线程
    class ThreadSubtract extends Thread {
    
        private String lock;
    
        public ThreadSubtract(String lock,String name) {
            super(name);
            this.lock = lock;
        }
    
        @Override
        public void run() {
            try {
                synchronized (lock) {
                    if (ValueObject.list.size() == 0) {
                        System.out.println("wait begin ThreadName=" + Thread.currentThread().getName());
                        lock.wait();
                        System.out.println("wait   end ThreadName=" + Thread.currentThread().getName());
                    }
                    ValueObject.list.remove(0);
                    System.out.println("list size=" + ValueObject.list.size());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    //测试类
    public class Run {
        public static void main(String[] args) throws InterruptedException {
    
            //锁对象
            String lock = new String("");
    
            ThreadSubtract subtract1Thread = new ThreadSubtract(lock,"subtract1Thread");
            subtract1Thread.start();
    
            ThreadSubtract subtract2Thread = new ThreadSubtract(lock,"subtract2Thread");
            subtract2Thread.start();
    
            Thread.sleep(1000);
    
            ThreadAdd addThread = new ThreadAdd(lock,"addThread");
            addThread.start();
    
        }
    }
    /* Output: 
            wait begin ThreadName=subtract1Thread
            wait begin ThreadName=subtract2Thread
            wait   end ThreadName=subtract2Thread
            list size=0
            wait   end ThreadName=subtract1Thread
            Exception in thread "subtract1Thread"
                java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
                at java.util.ArrayList.rangeCheck(Unknown Source)
                at java.util.ArrayList.remove(Unknown Source)
                at test.ThreadSubtract.run(Run.java:49)
     */

           当线程subtract1Thread被唤醒后,将从wait处继续执行。但由于线程subtract2Thread先获取到锁得到运行,导致线程subtr-act1Thread的wait的条件发生变化(不再满足),而 线程subtract1Thread 却毫无所知,导致异常产生。像这种有多个相同类型的线程场景,为防止wait的条件发生变化而导致的线程异常终止,我们在阻塞线程被唤醒的同时还必须对wait的条件进行额外的检查,如下所示:只需将 线程类ThreadSubtract 的 run()方法中的 if 条件 改为 while 条件 即可。

    //元素删除线程
    class ThreadSubtract extends Thread {
    
        private String lock;
    
        public ThreadSubtract(String lock,String name) {
            super(name);
            this.lock = lock;
        }
    
        @Override
        public void run() {
            try {
                synchronized (lock) {
                    while (ValueObject.list.size() == 0) {    //将 if 改成 while 
                        System.out.println("wait begin ThreadName=" + Thread.currentThread().getName());
                        lock.wait();
                        System.out.println("wait   end ThreadName=" + Thread.currentThread().getName());
                    }
                    ValueObject.list.remove(0);
                    System.out.println("list size=" + ValueObject.list.size());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /* Output: 
            wait begin ThreadName=subtract1Thread
            wait begin ThreadName=subtract2Thread
            wait   end ThreadName=subtract2Thread
            list size=0
            wait   end ThreadName=subtract1Thread
            wait begin ThreadName=subtract1Thread
     */

    三、Condition

           Condition是在java 1.5中出现的,它用来替代传统的Object的wait()/notify()实现线程间的协作,它的使用依赖于 Lock,Condition、Lock 和 Thread 三者之间的关系如下图所示。相比使用Object的wait()/notify(),使用Condition的await()/signal()这种方式能够更加安全和高效地实现线程间协作。Condition是个接口,基本的方法就是await()和signal()方法。Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition() 。 必须要注意的是,Condition 的 await()/signal() 使用都必须在lock保护之内,也就是说,必须在lock.lock()和lock.unlock之间才可以使用。事实上,Conditon的await()/signal() 与 Object的wait()-notify() 有着天然的对应关系:Conditon中的await()对应Object的wait();Condition中的signal()对应Object的notify();Condition中的signalAll()对应Object的notifyAll()。

    è¿éåå¾çæè¿°

           使用Condition往往比使用传统的通知等待机制(Object的wait()/notify())要更灵活、高效,例如,我们可以使用多个Condition实现通知部分线程:

    // 线程 A
    class ThreadA extends Thread {
        private MyService service;
        public ThreadA(MyService service) {
            super();
            this.service = service;
        }
        @Override
        public void run() {
            service.awaitA();
        }
    }
    // 线程 B
    class ThreadB extends Thread {
        public ThreadB(MyService service) {
            super();
            this.service = service;
        }
        @Override
        public void run() {
            service.awaitB();
        }
    }
    
    class MyService {
        private Lock lock = new ReentrantLock();
        // 使用多个Condition实现通知部分线程
        public Condition conditionA = lock.newCondition();
        public Condition conditionB = lock.newCondition();
    
        public void awaitA() {
            lock.lock();
            try {
                System.out.println("begin awaitA时间为" + System.currentTimeMillis()
                        + " ThreadName=" + Thread.currentThread().getName());
                conditionA.await();
                System.out.println("  end awaitA时间为" + System.currentTimeMillis()
                        + " ThreadName=" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void awaitB() {
            lock.lock();
            try {
                System.out.println("begin awaitB时间为" + System.currentTimeMillis()
                        + " ThreadName=" + Thread.currentThread().getName());
                conditionB.await();
                System.out.println("  end awaitB时间为" + System.currentTimeMillis()
                        + " ThreadName=" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void signalAll_A() {
            try {
                lock.lock();
                System.out.println("  signalAll_A时间为" + System.currentTimeMillis()
                        + " ThreadName=" + Thread.currentThread().getName());
                conditionA.signalAll();
            } finally {
                lock.unlock();
            }
        }
    
        public void signalAll_B() {
            try {
                lock.lock();
                System.out.println("  signalAll_B时间为" + System.currentTimeMillis()
                        + " ThreadName=" + Thread.currentThread().getName());
                conditionB.signalAll();
            } finally {
                lock.unlock();
            }
        }
    }
    
    // 测试
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyService service = new MyService();
    
            ThreadA a = new ThreadA(service);
            a.setName("A");
            a.start();
    
            ThreadB b = new ThreadB(service);
            b.setName("B");
            b.start();
    
            Thread.sleep(3000);
            service.signalAll_A();
        }
    }

           输出结果如下图所示,我们可以看到只有线程A被唤醒,线程B仍然阻塞。实际上,Condition 实现了一种分组机制,将所有对临界资源进行访问的线程进行分组,以便实现线程间更精细化的协作,例如通知部分线程。我们可以从上面例子的输出结果看出,只有conditionA范围内的线程A被唤醒,而conditionB范围内的线程B仍然阻塞。

    å¤ä¸ªConditionéç¥é¨å线ç¨.png-13.1kB

    四、生产者/消费者模式

             等待/通知机制 最经典的应用就是 生产者-消费者模型。下面以多生产者-多消费者问题为背景,分别运用两种模式 —— synchronized+wait-notify模式和Lock+Condition模式实现 wait-notify 机制。示例一传统实现:

    //资源类
    class MyStack {
        // 共享队列
        private List list = new ArrayList();
    
        // 生产
        @SuppressWarnings("unchecked")
        public synchronized void push() {
            try {
                while (list.size() == 1) {    // 多个生产者
                    System.out.println("队列已满,线程 "
                            + Thread.currentThread().getName() + " 呈wait状态...");
                    this.wait();
                }
                list.add("anyString=" + Math.random());
                System.out.println("线程 " + Thread.currentThread().getName()
                        + " 生产了,队列已满...");
                this.notifyAll();                   // 防止生产者仅通知生产者
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        // 消费
        public synchronized String pop() {
            String returnValue = "";
            try {
                while (list.size() == 0) {              // 多个消费者
                    System.out.println("队列已空,线程 "
                            + Thread.currentThread().getName() + " 呈wait状态...");
                    this.wait();
                }
                returnValue = "" + list.get(0);
                list.remove(0);
                System.out.println("线程 " + Thread.currentThread().getName()
                        + " 消费了,队列已空...");
                this.notifyAll();                   // 防止消费者仅通知消费者
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return returnValue;
        }
    }
    
    //生产者
    class P_Thread extends Thread {
    
        private MyStack myStack;
    
        public P_Thread(MyStack myStack,String name) {
            super(name);
            this.myStack = myStack;
        }
    
        public void pushService() {
            myStack.push();
        }
    
        @Override
        public void run() {
            while (true) {     
                myStack.push();
            }
        }
    }
    
    //消费者
    class C_Thread extends Thread {
    
        private MyStack myStack;
    
        public C_Thread(MyStack myStack,String name) {
            super(name);
            this.myStack = myStack;
        }
    
        @Override
        public void run() {
            while (true) {
                myStack.pop();
            }
        }
    }
    
    //测试类
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyStack myStack = new MyStack();
    
            P_Thread pThread1 = new P_Thread(myStack, "P1");
            P_Thread pThread2 = new P_Thread(myStack, "P2");
            P_Thread pThread3 = new P_Thread(myStack, "P3");
            P_Thread pThread4 = new P_Thread(myStack, "P4");
            P_Thread pThread5 = new P_Thread(myStack, "P5");
            P_Thread pThread6 = new P_Thread(myStack, "P6");
            pThread1.start();
            pThread2.start();
            pThread3.start();
            pThread4.start();
            pThread5.start();
            pThread6.start();
    
            C_Thread cThread1 = new C_Thread(myStack, "C1");
            C_Thread cThread2 = new C_Thread(myStack, "C2");
            C_Thread cThread3 = new C_Thread(myStack, "C3");
            C_Thread cThread4 = new C_Thread(myStack, "C4");
            C_Thread cThread5 = new C_Thread(myStack, "C5");
            C_Thread cThread6 = new C_Thread(myStack, "C6");
            C_Thread cThread7 = new C_Thread(myStack, "C7");
            C_Thread cThread8 = new C_Thread(myStack, "C8");
            cThread1.start();
            cThread2.start();
            cThread3.start();
            cThread4.start();
            cThread5.start();
            cThread6.start();
            cThread7.start();
            cThread8.start();
        }
    }
    /* Output: 
            线程 P1 生产了,队列已满...
            队列已满,线程 P1 呈wait状态...
            线程 C5 消费了,队列已空...
            队列已空,线程 C5 呈wait状态...
            队列已空,线程 C8 呈wait状态...
            队列已空,线程 C2 呈wait状态...
            队列已空,线程 C7 呈wait状态...
            队列已空,线程 C4 呈wait状态...
            队列已空,线程 C6 呈wait状态...
            队列已空,线程 C3 呈wait状态...
            队列已空,线程 C1 呈wait状态...
            线程 P6 生产了,队列已满...
            队列已满,线程 P6 呈wait状态...
            队列已满,线程 P5 呈wait状态...
            队列已满,线程 P4 呈wait状态...
            ...
     */
    

           对于生产者-消费者问题,有两个要点需要注意:第一,在多个同类型线程(多个生产者线程或者消费者线程)的场景中,为防止wait的条件发生变化而导致线程异常终止,我们在阻塞线程被唤醒的同时还必须对wait的条件进行额外的检查,即 使用 while 循环代替 if 条件;第二,在多个同类型线程(多个生产者线程或者消费者线程)的场景中,为防止生产者(消费者)唤醒生产者(消费者),保证生产者和消费者互相唤醒,需要 使用 notify 替代 notifyAll。示例二,使用condition方式实现:

    // 线程A
    class MyThreadA extends Thread {
    
        private MyService myService;
    
        public MyThreadA(MyService myService, String name) {
            super(name);
            this.myService = myService;
        }
    
        @Override
        public void run() {
            while (true)
                myService.set();
        }
    }
    
    // 线程B
    class MyThreadB extends Thread {
    
        private MyService myService;
    
        public MyThreadB(MyService myService, String name) {
            super(name);
            this.myService = myService;
        }
    
        @Override
        public void run() {
            while (true)
                myService.get();
        }
    }
    
    // 资源类
    class MyService {
    
        private ReentrantLock lock = new ReentrantLock();
        private Condition conditionA = lock.newCondition();   // 生产线程
        private Condition conditionB = lock.newCondition();  // 消费线程
        private boolean hasValue = false;
    
        public void set() {
            try {
                lock.lock();
                while (hasValue == true) {
                    System.out.println("[生产线程] " + " 线程"
                            + Thread.currentThread().getName() + " await...");
                    conditionA.await();
                }
                System.out.println("[生产中] " + " 线程" + Thread.currentThread().getName() + " 生产★");
                Thread.sleep(1000);
                hasValue = true;
                System.out.println("线程" + Thread.currentThread().getName() + " 生产完毕...");
                System.out.println("[唤醒所有消费线程] " + " 线程"
                        + Thread.currentThread().getName() + "...");
                conditionB.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void get() {
            try {
                lock.lock();
                while (hasValue == false) {
                    System.out.println("[消费线程] " + " 线程"
                            + Thread.currentThread().getName() + " await...");
                    conditionB.await();
                }
                System.out.println("[消费中] " + " 线程"
                        + Thread.currentThread().getName() + " 消费☆");
                Thread.sleep(1000);
                System.out.println("线程" + Thread.currentThread().getName() + " 消费完毕...");
                hasValue = false;
                System.out.println("[唤醒所有生产线程] " + " 线程"
                        + Thread.currentThread().getName() + "...");
                conditionA.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyService service = new MyService();
    
            MyThreadA[] threadA = new MyThreadA[10];
            MyThreadB[] threadB = new MyThreadB[10];
    
            for (int i = 0; i < 10; i++) {
                threadA[i] = new MyThreadA(service, "ThreadA-" + i);
                threadB[i] = new MyThreadB(service, "ThreadB-" + i);
                threadA[i].start();
                threadB[i].start();
            }
        }
    }
    /* Output: 
            [生产中]  线程ThreadA-0 生产★
            线程ThreadA-0 生产完毕...
            [唤醒所有消费线程]  线程ThreadA-0...
            [生产线程]  线程ThreadA-0 await...
            [消费中]  线程ThreadB-0 消费☆
            线程ThreadB-0 消费完毕...
            [唤醒所有生产线程]  线程ThreadB-0...
            [消费线程]  线程ThreadB-0 await...
            [生产中]  线程ThreadA-1 生产★
            线程ThreadA-1 生产完毕...
            [唤醒所有消费线程]  线程ThreadA-1...
            [生产线程]  线程ThreadA-1 await...
            [消费中]  线程ThreadB-1 消费☆
            线程ThreadB-1 消费完毕...
            [唤醒所有生产线程]  线程ThreadB-1...
            [消费线程]  线程ThreadB-1 await...
            [生产中]  线程ThreadA-2 生产★
            线程ThreadA-2 生产完毕...
            [唤醒所有消费线程]  线程ThreadA-2...
            ...
     */

    五、线程间的通信——管道

            PipedInputStream类 与 PipedOutputStream类 用于在应用程序中创建管道通信。一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进行连接而产生一个通信管道。PipedOutputStream可以向管道中写入数据,PipedIntputStream可以读取PipedOutputStream向管道中写入的数据,这两个类主要用来完成线程之间的通信。一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据,如下图所示:
    线ç¨é信示æå¾ä¹ç®¡é.jpg-30.5kB

           PipedInputStream和PipedOutputStream的实现原理类似于”生产者-消费者”原理,PipedOutputStream是生产者,PipedInputStream是消费者。在PipedInputStream中,有一个buffer字节数组,默认大小为1024,作为缓冲区,存放”生产者”生产出来的东西。此外,还有两个变量in和out —— in用来记录”生产者”生产了多少,out是用来记录”消费者”消费了多少,in为-1表示消费完了,in==out表示生产满了。当消费者没东西可消费的时候,也就是当in为-1的时候消费者会一直等待,直到有东西可消费。在Java的JDK 中提供了四个类用于线程间通信字节流——PipedInputStream和PipedOutputStream;字符流——PipedReader和PipedWriter;
     

    //读线程
    class ThreadRead extends Thread {
    
        private ReadData read;
        private PipedInputStream input;
    
        public ThreadRead(ReadData read, PipedInputStream input) {
            super();
            this.read = read;
            this.input = input;
        }
    
        public void readMethod(PipedInputStream input) {
            try {
                System.out.println("read  :");
                byte[] byteArray = new byte[20];
                int readLength = input.read(byteArray);
                while (readLength != -1) {
                    String newData = new String(byteArray, 0, readLength);
                    System.out.print(newData);
                    readLength = input.read(byteArray);
                }
                System.out.println();
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            this.readMethod(input);
        }
    }
    
    //写线程
    class ThreadWrite extends Thread {
    
        private WriteData write;
        private PipedOutputStream out;
    
        public ThreadWrite(WriteData write, PipedOutputStream out) {
            super();
            this.write = write;
            this.out = out;
        }
    
        public void writeMethod(PipedOutputStream out) {
            try {
                System.out.println("write :");
                for (int i = 0; i < 30; i++) {
                    String outData = "" + (i + 1);
                    out.write(outData.getBytes());
                    System.out.print(outData);
                }
                System.out.println();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            this.writeMethod(out);
        }
    }
    
    //测试
    public class Run {
    
        public static void main(String[] args) {
            try {
                WriteData writeData = new WriteData();
                ReadData readData = new ReadData();
    
                PipedInputStream inputStream = new PipedInputStream();
                PipedOutputStream outputStream = new PipedOutputStream();
    
                // inputStream.connect(outputStream);   // 效果相同
                outputStream.connect(inputStream);
    
                ThreadRead threadRead = new ThreadRead(readData, inputStream);
                threadRead.start();
    
                Thread.sleep(2000);
    
                ThreadWrite threadWrite = new ThreadWrite(writeData, outputStream);
                threadWrite.start();
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /* Output: 
            read  :
            write :
            123456789101112131415161718192021222324252627282930
            123456789101112131415161718192021222324252627282930
     */

    六、方法Join的使用

           1. join() 的定义

           假如在main线程中调用thread.join方法,则main线程会等待thread线程执行完毕或者等待一定的时间。详细地,如果调用的是无参join方法,则等待thread执行完毕;如果调用的是指定了时间参数的join方法,则等待一定的时间。join()方法有三个重载版本:

    public final synchronized void join(long millis) throws InterruptedException {...}
    public final synchronized void join(long millis, int nanos) throws InterruptedException {...}
    public final void join() throws InterruptedException {...}
    

             以 join(long millis) 方法为例,其内部调用了Object的wait()方法,如下图:

    join çå®ä¹.png-39.6kB

          根据以上源代码可以看出,join()方法是通过wait()方法 (Object 提供的方法) 实现的。当 millis == 0 时,会进入 while(isAlive()) 循环,并且只要子线程是活的,宿主线程就不停的等待。 wait(0) 的作用是让当前线程(宿主线程)等待,而这里的当前线程是指 Thread.currentThread() 所返回的线程。所以,虽然是子线程对象(锁)调用wait()方法,但是阻塞的是宿主线程。
           2.join() 使用实例及原理

    //示例代码
    public class Test {
    
        public static void main(String[] args) throws IOException  {
            System.out.println("进入线程"+Thread.currentThread().getName());
            Test test = new Test();
            MyThread thread1 = test.new MyThread();
            thread1.start();
            try {
                System.out.println("线程"+Thread.currentThread().getName()+"等待");
                thread1.join();
                System.out.println("线程"+Thread.currentThread().getName()+"继续执行");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } 
    
        class MyThread extends Thread{
            @Override
            public void run() {
                System.out.println("进入线程"+Thread.currentThread().getName());
                try {
                    Thread.currentThread().sleep(5000);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"执行完毕");
            }
        }
    }
    /* Output:
            进入线程main
            线程main等待
            进入线程Thread-0
            线程Thread-0执行完毕
            线程main继续执行
     */

           看上面的例子,当 main线程 运行到 thread1.join() 时,main线程会获得线程对象thread1的锁(wait 意味着拿到该对象的锁)。只要 thread1线程 存活, 就会调用该对象锁的wait()方法阻塞 main线程。那么,main线程被什么时候唤醒呢?事实上,有wait就必然有notify。在整个jdk里面,我们都不会找到对thread1线程的notify操作。这就要看jvm代码了:

    //一个c++函数:
    void JavaThread::exit(bool destroy_vm, ExitType exit_type) ;
    
    //这个函数的作用就是在一个线程执行完毕之后,jvm会做的收尾工作。里面有一行代码:ensure_join(this);
    
    该函数源码如下:
    
    static void ensure_join(JavaThread* thread) {
        Handle threadObj(thread, thread->threadObj());
    
        ObjectLocker lock(threadObj, thread);
    
        thread->clear_pending_exception();
    
        java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
    
        java_lang_Thread::set_thread(threadObj(), NULL);
    
        //thread就是当前线程,就是刚才说的thread1线程。
        lock.notify_all(thread);
    
        thread->clear_pending_exception();
    }

           至此,thread1线程对象锁调用了notifyall,那么main线程也就能继续跑下去了。由于 join方法 会调用 wait方法 让宿主线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。结合 join 方法的声明,可以总结出以下三条:join方法同样会会让线程交出CPU执行权限;join方法同样会让线程释放对一个对象持有的锁;如果调用了join方法,必须捕获InterruptedException异常或者将该异常向上层抛出。


    原文链接地址:https://blog.csdn.net/justloveyou_/article/details/54929949

    展开全文
  • java线程通信的三种方式

    千次阅读 2019-04-02 14:26:08
    1、传统的线程通信。 在synchronized修饰的同步方法或者修饰的同步代码块中使用Object类提供的wait(),notify()和notifyAll()3个方法进行线程通信。 关于这3个方法的解释: wait():导致当前线程等待,直到其他线程...

    1、传统的线程通信。

        在synchronized修饰的同步方法或者修饰的同步代码块中使用Object类提供的wait(),notify()和notifyAll()3个方法进行线程通信。

        关于这3个方法的解释:

        wait():导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程。
        notify():唤醒在此同步监视器上等待的单个线程。
        notifyAll():唤醒在此同步监视器上等待的所有线程。


    2、使用Condition控制线程通信。

        当程序使用Lock对象来保证同步,系统不存在隐式的同步监视器,只能用Condition类来控制线程通信。

         await():类似于隐式同步监视器上的wait()方法,导致当前线程等待,直到其他线程调用该Condition的signal()方法或signalAll()方法来唤醒该线程。
        signal():唤醒在此Lock对象上等待的单个线程。如果所有的线程都在该Lock对象上等待,则会选择唤醒其中一个线程。选择是任意性的。
        signalAll():唤醒在此Lock对象上等待的所有线程,只有当前线程放弃对该Lock对象的锁定后,才可以执行被唤醒的线程。

     

    3、使用阻塞队列(BlockingQueue)控制线程通信(也实现了生产者消费者模式)

        BlockingQueue提供如下两个支持阻塞的方法:
        put(E e):尝试把E元素放入BlockingQueue中,如果该队列的元素已满,则阻塞该线程。
        take():尝试从BlockingQueue的头部取出元素,如果该队列的元素已空,则阻塞该线程。
        示例代码如下:
        
    package edu.Utils;
     
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
     
    /**
     * Created by hpp on 2017/7/4.
     */
     
    class Producer extends Thread{
        private BlockingQueue<String> bq;
        public Producer(BlockingQueue<String> bq){
            this.bq = bq;
        }
        public void run(){
            String[] strArr = new String[]{
                    "java",
                    "Struts",
                    "Spring"
            };
            for(int i = 0;i<99999;i++){
                System.out.println(getName() + "生产者准备生产集合元素!");
                try{
                    Thread.sleep(1000);
                    bq.put(strArr[i%3]);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println(getName() + "生成完成:" + bq);
            }
        }
    }
     
    class Consumer extends Thread{
        private BlockingQueue<String> bq;
        public Consumer(BlockingQueue<String> bq){
            this.bq = bq;
        }
        public void run(){
            while(true){
                System.out.println(getName() + "消费者准备消费集合元素!");
                try{
                    Thread.sleep(1000);
                    bq.take();
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println(getName() + "消费完成:" + bq);
            }
        }
    }
     
     
    public class BlockingQueueTest {
     
        public static void main(String[] args){
            //创建一个容量为1的BlockingQueue
            BlockingQueue<String> bq = new ArrayBlockingQueue<String>(1);
            //启动3个生产者线程
            new Producer(bq).start();
            new Producer(bq).start();
            new Producer(bq).start();
            //启动1个消费者线程
            new Consumer(bq).start();
     
        }
     
    }
    运行结果:
    Thread-0生产者准备生产集合元素!
    Thread-1生产者准备生产集合元素!
    Thread-2生产者准备生产集合元素!
    Thread-3消费者准备消费集合元素!
    Thread-0生成完成:[java]
    Thread-0生产者准备生产集合元素!
    Thread-1生成完成:[java]
    Thread-1生产者准备生产集合元素!
    Thread-3消费完成:[java]
    Thread-3消费者准备消费集合元素!
    Thread-2生成完成:[java]
    Thread-2生产者准备生产集合元素!
    Thread-3消费完成:[java]
    Thread-3消费者准备消费集合元素!
    Thread-0生成完成:[Struts]
    Thread-0生产者准备生产集合元素!
    Thread-3消费完成:[Struts]
    Thread-3消费者准备消费集合元素!
     

    展开全文
  • 本源代码是博客《Java线程编程之六:线程之间的通信(附源代码)》附带的实例性源代码。原博客链接地址:http://blog.csdn.net/defonds/archive/2010/01/26/5257301.aspx。
  • 本文实现一个线程通信的例子:三个线程交替打印1-100。
  • 线程通信: 注意三个都是Object的方法 并且都必须在synchronzied代码块和安全方法下使用否则会报异常 wiat:使当前线程挂起,释放锁,其他线程可以参与进来共享其数据。 notify:唤醒当前线程,让线程握住锁,其他...
  • 创建两个线程,交替打印1到100之间的整数。
  • 多任务和高并发是衡量一台计算机处理器的能力重要指标之一。一般衡量一个服务器性能的...在讨论Java内存模型和线程之前,先简单介绍一下硬件的效率与一致性。 硬件的效率与一致性 由于计算机的存储设备与处理器的运算
  • Java 常见线程通信生产消费案例演示

    千次阅读 2020-03-18 13:02:51
    介绍了Java线程通信的原理、目的、方法,在文章最后给出了多个线程通信案例。
  • 本文主要介绍java 多线程-线程通信 这里整理了相关资料及示例代码,有兴趣的小伙伴可以参考下
  • Java线程(九):Condition-线程通信更高效的方式

    万次阅读 多人点赞 2012-04-20 14:49:39
    接近一周没更新《Java线程》专栏了,主要是这周工作上比较忙,生活上也比较忙,呵呵,进入正题,上一篇讲述了并发包下的Lock,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更...
  • 主要介绍了Java线程通信实现方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 服务器通信学习
  • java线程通信图解

    2017-11-29 20:03:50
    java线程 其实就是每个线程都拥有自己的内存空间,多线程之间的通信,比例A线程修改了主内存(main方法的线程)变量,需要把A线程修改的结果同步到主线程中,这时B线程再从主线程获取该变量的值,这样就实现了...
  • 主要介绍了Java Socket实现多线程通信功能,结合具体实例形式较为详细的分析了java线程通信的原理及客户端、服务器端相应实现技巧,需要的朋友可以参考下
  • 主要介绍了Java线程通信:交替打印ABAB实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要介绍了java线程间通信的通俗解释,介绍了线程通信中的几个相关概念,然后分享了线程通信的实现方式及代码示例,具有一定参考价值 ,需要的朋友可以了解下。
  • 主要介绍了Java Socket实现单线程通信的方法,结合具体实例形式分析了java socket单线程通信的原理与客户端、服务器端相关实现技巧,需要的朋友可以参考下
  •  多线程通信,其实是多个线程操操作同一个资源,但是操作方式不同。典型实例有生产者和消费者,本文也通过实例来分析线程等待唤醒机制。  1、相关API介绍  public final void notify()  唤醒在此对象监视...
  • java实现线程通信的几种方式

    千次阅读 2020-05-30 19:34:35
    比如大家熟知的消息中间件的实现,从某种角度上讲,就借助了多线程通信的思想,下面总结了JDK中常用的几种实现线程通信的方式,提供参考 1、synchronized实现方式 可能很多小伙伴们会有疑问,synchronized是对共享...
  • 一个多线程通信服务端程序的简单例子,可以根据情况增加业务逻辑。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 254,385
精华内容 101,754
关键字:

java线程通信

java 订阅