首页 > 编程知识 正文

线程间如何通信,java多线程通信机制

时间:2023-05-05 05:51:35 阅读:61971 作者:4685

文章前言使用同步线程通信相关方法“Condition”的线程通信使用使用块队列“BlockingQueue”的线程通信线程组和未处理异常

前言

如果线程在系统中运行,则程序无法准确控制线程的轮换运行。 Java提供了一种用于确保线程协调运行的机制。

同步线程通信相关的方法是Object类提供的wait ()、notify ()和notifyAll () )这三个方法(不属于Thread类),这三个方法必须由同步监视器调用这可以分为以下情况。

对于同步方法,类的缺省实例(this )是同步监视器,因此可以在同步方法中直接调用这三个方法。 对于同步代码块,同步监视器是位于同步后括号中的对象,因此将使用此对象调用。 关于这三种方法的说明:

wit ()等待当前线程,直到其他线程调用同步监视器的notify ) )或notifyAll )方法来启动线程。 没有参与就一直等待,有参与就在长毫秒的时间里等待自动觉醒。 notify () )唤醒在此同步监视器上等待的一个线程,如果多个线程在等待同步监视器,则随机唤醒其中一个线程。 只有当前线程主动放弃锁定时,唤醒的线程才会运行。 通告所有(:启动在此同步监视器上等待的所有线程。 如果不使用Condition线程通信同步关键字来确保线程同步,而是使用Lock对象来确保线程同步,则系统中不存在隐式同步监视器,wait (、notify )、notify 因此,如果使用Lock对象来确保同步,Java将提供Condition类来确保协调。 通过Condition,即使已获取Lock对象,也无法执行的线程也可以释放Lock对象,并唤醒等待的其他线程。

Condition将同步监视器方法(wait (、notify )、notifyAll () ) )分为不同的对象,以方便与Lock对象的合并。 Lock代替同步方法和代码块,Condition代替同步监视器功能。 Condition实例绑定到Lock对象,要获取Lock对象的Condition实例,请调用Lock对象的newCondition ()方法。

Condition类提供以下方法:

await ()是一种wait ) (如隐式同步监视器)方法,它是当前线程,直到其他线程调用Condition的signal ()或signalAll () )方法来唤醒线程派生的方法有很多。 awaitUninterruptibly (,awaituntil )、datedeadline )。 signal () )唤醒在此Lock对象上等待的一个线程,如果有多个线程等待,则随机唤醒其中一个线程。 signalAll (:唤醒在此Lock对象上等待的所有线程。 只有在当前线程解除对此Lock对象的锁定后,才能执行被唤醒的线程。 使用“阻塞队列”(BlockingQueue )的线程通信Java5提供了一个Queue子接口,但其主要方法是线程同步而不是容器BlockingQueue具有特点。 当生产者线程尝试将元素放入BlockingQueue时,如果该队列已满,则该线程将被阻止;当消费者线程尝试从BlockingQueue中检索元素时,如果该队列为空,则该线程将被阻止

通过将程序的两个线程交替放入BlockingQueue并取出元素,可以控制线程通信。 阻塞队列有两种方法:

put(t ) :将t元素放入BlockingQueue中,队列满后阻止线程。 take () :从BlockingQueue的开头检索元素,如果队列元素为空,则阻止线程。 阻塞队列继承了队列接口。 当然,也可以使用Queue接口的方法。

在团队末尾插入元素。 包括add(tt )、offer )和put (t )方法,当队列已满时,这三个方法分别抛出异常并返回false以阻止队列。 在队列开头删除元素并返回。 包括remove ()、poll ()和take )方法,如果队列为空,则这三个方法中的每一个都会抛出异常并返回false以阻止队列。 在队伍的最前面只取出元素。 如果队列为空,则包含抛出异常并返回false的element (,peek )方法。 可以用下表表示。

如果抛出异常并在指定false块线程的超时时间内队列已满,请在队列末尾插入元素add () offer ()、put ()、offer (e )、time和unit ),当队列为空时

ArrayBlockingQueue :基于数组实现的BlockingQueue队列。 LinkedBlockingQueue :基于链表实现的BlockingQueue队列。 同步队列:必须同步队列并交替访问该队列。 PriorityBlockingQueue :不是标准的块队列。 与PriorityQueue一样,此队列在调用remove (,poll )、take )方法检索元素时不是这样

是取出队列中存在时间最长的元素,而是最小的元素。判断元素大小可根据元素(实现Comparable接口)的本身大小进行自然排序,也可使用Comparator自定义排序。DelayQueue:底层基于PriorityBlockingQueue实现,要求元素都实现Delay接口,接口里只有一个long getDelay()方法,DelayQueue根据元素的getDelay()方法的返回值进行排序。 public class BlockingQueueTest{ public static void main(Strings[] args) throws Exception{ BlockingQueue<String> b = new ArrayBlockingQueue<>(2); b.put("阻塞队列"); b.put("阻塞队列"); b.put("阻塞队列");//队列已满,阻塞线程 }} 线程组和未处理异常

Java使用ThreadGroup来表示线程组,它可以对一批线程进行管理,允许程序直接对线程进行控制。如果没有显式指定创建的线程属于哪个线程组,则属于默认线程组。默认情况下,子线程和创建它的线程属于同一线程组。一旦线程加入了指定的线程组,则该线程一直属于该线程组,直至死亡不能改变。

Thread类提供了如下几个构造器来设置创建的线程属于哪个线程组:

Thread(ThreadGroup group,Runnable target):以target的run方法作为线程执行体创建新的线程,属于group线程组Thread(ThreadGroup group,Runnable target,String name):同样的,只不过指定了创建的线程名字。Thread(ThreadGroup group,String name):创建新线程,指定线程名。

虽然不能改变所在指定的线程组,但可以通过getTreadGroup()方法返回所属线程组,返回值是ThreadGroup对象。而ThreadGroup类提供了两个构造器创建相应实例:

ThreadGroup(String name):以指定的线程组名字来创建新的线程组。ThreadGroup(ThreadGroup parent,String name):以指定的的名字和父线程组创建新的线程组。

通过以上构造器可以发现,线程组必然有一个名字,这个名字可以通过ThreadGroup的getName()方法获取,但是不允许改变线程组的名字,也就没有set方法。除了构造器,ThreadGroup还提供了几个方法来操作线程组里的所有线程:

activeCount():返回线程组中活动线程的数目。interrupt():中断此线程组的所有线程。isDaemon():判断该线程组是否是后台线程组。setDaemon():把线程组设置为后台线程组,若后台线程组的最后一个线程死亡,则线程组自动毁灭。setMaxPriority(int p):设置线程组的最高优先级。

此外,线程组对于出现的异常也提供了一个方法void uncaughtException(Thread t,Throwable e),该方法可以处理该线程组内的任意线程所抛出的未处理异常。如果线程抛出一个异常,JVM会在线程结束前自动查找对应的Thread.UncaughtExceptionHandler对象,如果找到该异常处理器对象,则会调用该对象的uncaughtException(Thread t,Throwable e)方法处理异常。

Thread.UncaughtExceptionHandler是Thread类的一个静态内部接口,里面只有一个方法uncaughtException(Thread t,Throwable e),t代表异常的线程,e代表抛出的异常。Thread类提供了如下方法来设置异常处理器:

static setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h):为该线程类的所有实例设置默认异常处理器。setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h):为线程实例设置异常处理器。

ThreadGroup类实现了Thread.UncaughtExceptionHandler接口,所以每个线程的线程组都将作为默认的异常处理器。当一个线程抛出异常时,JVM会先查找线程实例指定的异常处理器,否则会调用所属线程组对象的uncaughtException()方法(默认的异常处理器)处理异常。

线程组默认异常处理器处理过程如下:

如果该线程组有父线程组,则调用父线程组的uncaughtException()方法处理。如果该线程所属的默认线程组有默认异常处理器,那么就调用该异常处理器处理。如果该异常是ThreadDeath的对象,则不做任何处理,否则将异常跟踪栈的信息打印到System.err输出流,并结束该线程。 Class MyHandler implements Thread.UncaughtExceptionHandler{//自定义处理器 public void uncaughtException(Thread t,Throwable e){ System.out.println(t+" 出现异常 "+e); }}public class ExHandler{ public static void main(String[] args){ Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler()); int a = 1/0;//ArithmeticException System.out.println("程序已结束!");//不会正常结束,所以不会输出 }}

上诉代码虽然捕获了异常,但是出现不会正常结束。因为与try...catch异常捕获不同,异常处理器对异常进行处理后会将异常抛给上一级调用者,而catch捕获异常不会。

以上就是整理的有关线程通信的全部知识了,希望能在多线程通信上对大家有所帮助!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。