Java多线程设计模式(1)

简介:

1 线程中的几个方法解释

Thread.sleep(long 毫秒)

在指定的时间内让当前线程休眠,将控制权交给其他线程,休眠的线程依旧拥有它所占用的锁

Thread.yield();

暂停或者放弃当前正在执行的线程,并且执行其他线程,但是并没有释放该线程所拥有的锁,线程放弃后,让其他相同或者更高线程得以运行。

t.join()

A线程中等待t线程,可以指定一定时间后继续执行或者无限等待

t.interrupt()

中断t的线程,可以唤醒打断处于sleepjoinwait状态下的线程,

p.wait()

线程可以等待一个它锁定的对象,在等待的时候,它会释放此对象的锁并且暂停进入休眠,它会在时间到期、该线程被中断和对象得到通知之前一直保持休息。直到它得到了其他线程的通知,如该对象调用notify()notifyAll()的时候才会执行

对于使用wait和notify与notifyAll的时候均要先利用同步代码块或者同步方法获取该对象的锁,利用wait后,会首先获取该对象锁,然后进入该对象的wait set中,暂停当前的线程,释放该对象的锁,在该对象的wait set等待着

对于直接wait()就是this.wait(),执行wait()的线程会在this的wait set中等待着。

Yield和Sleep区别

       sleep 方法使当前运行中的线程睡眠一段时间,进入不可以运行状态,这段时间的长短是由程序设定的,它只有被吵醒或者睡眠时间到才会继续运行;

       yield方法使当前线程让出CPU占有权即时间片,重新排队,但让出的时间是不可设定的,该线程依然是可运行状态

       yield()方法对应了如下操作:先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把CPU的占有权交给该线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它把运行机会让给了同等级的其他线程。

sleep 方法允许较低优先级的线程获得运行机会yield()方法执行时,当前线程仍处在运行状态,它在队列中等候cpu调用,所以说是可运行状态(注意不是运行状态),所以不可能让出较低优先级的线程此时获取CPU占有权。在一个运行系统中,如果较高优先级的线程没有调用sleep方法,也没有受到I/O阻塞,那么较低优先级线程只能等待所有较高优先级的线程运行结束,方可有机会运行。

yield()只是使当前线程重新回到可运行状态,所有执行yield()的线程有可能在进入到可运行状态后马上又被执行,所以yield()方法只能使同优先级的线程有执行的机会
2 线程的启动

   线程的启动永远都是调用Start()方法开始的, Thread.start ()方法启动线程,使之进入就绪状态,当 cpu 分配时间片给该线程时,由 JVM 调度执行 run ()方法之所以要startrun方法的原因是,因为 JVM 创建一个单独的线程不同于普通方法的调用,启动一个线程是由start 方法完成,start 由本地方法实现,需要显示地被调用。Run方法是真正执行的任务部分,另一个好处就是在于当一个对象需要继承多类的时候,此时就可以将具体的任务实现了 Runnable 接口,然后传递给Thread中,避免因继承了 Thread 类而造成的 Java 的多继承问题。

   对于同一个Thread类的实例变量,只能调用一次Start方法,一旦调用start方法,就会变成结束start状态,当其再次调用start方法的时候,就会出现IllegalThreadStateException,就会进行退让让线程的启动不会再次执行。Thread类的start方法采用的就是Balking Pattern模式。

   多线程都是针对多个线程操作同一个对象下作用的。


3 Single Threaded Execution Pattern

   Single Threaded Execution指的就是“只允许一个线程执行”的意思,它表明对于调用这个方法或对象的时候必须只能让一个线程来执行。利用synchronized来设置对象的监听器,在synchronized方法体或者同步块中。必须要注意synchronized实例方法共享的是类的实例对象的锁,而synchronized类方法即static synchronized的方法共享的是类的锁,这两把锁完全不同。

   对于一个对象的某一个方法,当有多个线程需要访问的时候,这些线程是共享这个对象的所有成员属性的。线程是共享这个对象的内存。

   Single Threaded Execution中,作为共享资源的类,即可以被多个线程访问的。有两种方法,安全方法和非安全方法,所谓的安全方法就是多个线程调用也不会出现问题。而非安全方法在多个线程访问的过程可能会出现问题。需要对于非安全方法做处理。
适用性:当共享资源类的实例可能被多个线程访问的时候,实例的状态即属性会被修改,在多个线程中,此时就需要对于对于实例的状态发生变化的范围作为临界区,利用synchronized来保护,实现临界区间,来监听多线程的访问。


4 Immutable Pattern

   Immutable Pattern指的就是“有着能够保证实例的状态绝不会发生变化更改的类”,再次说明这里指实例的状态都是指的是类的成员属性。所谓的不能发生变化,也就是对于类的状态只允许赋值一次,且不会给外界提供任何setter方法,并且属性是private final,一般通过在构造器来对于这些状态赋值,当然也可以将类声明为final。利用这种方式,就克服利用共享互斥机制来造成的时间浪费。

   Immutable Pattern参与者是一个字段值无法更改的类,也没有任何用来更改字段值的方法。当Immutable参与者的实例一旦创建后,状态就固定下来,无法更改了。
适用性:当实例产生后,状态不再发生变化。实例需要多个线程共享,访问很频繁的时候。


5 Guarded Suspension Pattern--要等到我准备好再通知你们哟

  Guarded Suspension指的意思是“在多线程中,当线程访问某一个资源时候,此时并不适合马上执行某个操作时,就要求想要执行该操作的线程必须等待。”Guarded是“被保护的”,suspension是“暂停”的意思。

  Guarded Suspension要求线程必须等待。利用的就是wait,再通过notifyAll来通知所有等待的线程。将线程要执行某一个操作,必须满足的条件称为警戒条件。每个线程在执行的时候,如果不满足警戒条件就必须在等待,只有收到通知后,判断警戒条件成功后,才能进而执行所要的目的操作。

  常用的警戒条件结构如下:

 public synchronized void methodName()

 {

      while(警戒条件的否定)

          使用wait;//这里直接在共享类中wait,所有等待的都会进入该类实例的this wait set中等候

     //跳出循环,说明满足警戒条件

      执行目的操作。

  }
注:不能将while替换为if,因为凡是处于等待中的线程一旦获得唤醒,就必须在执行目的操作之前先进行警戒条件的判断才能进而执行目的操作。必须将捕获wait的异常包括在while循环体中,否则一旦发生异常可能就会进而执行目的操作。这里的wait也不能换为sleep,因为利用sleep该线程会一直拥有它所获得锁。

在这里wait和notify都是隐藏在共享资源中,这样凡是使用该共享资源的线程就不需要考虑这些问题了。

GuardedObject参与者是一个拥有被防卫的方法guardedMethod,一般就是利用synchronized来修饰,在线程执行这个方法的时候,只要满足警戒条件就会执行,否则就会一直等待。警戒条件会随着实例的状态变化而变化。还需要一个更改实例状态的方法stateChangingMethod,来通知那些等待的线程。

一般使用while语句和wait方法来实现guardedMethod,使用notify和notifyAll来实现stateChangingMethod


6 Balking Pattern

 Balking Pattern指的是“多线程访问共享资源时候,当现在不适合进行这个操作,或者没有必要进行这个操作的时候,此时就会直接放弃进行这个操作而返回”。

 Balking Pattern也是需要警戒条件的。GuardedObject参与者是一个拥有被防卫的方法guardedMethod,一般就是利用synchronized来修饰,在线程执行这个方法的时候,只要满足警戒条件就会执行,否则就会。警戒条马上返回,直接退出该方法。警戒条件的成立会随着实例的状态变化而变化。还需要一个更改实例状态的方法stateChangingMethod,来通知那些等待的线程。

  警戒条件的结构:

 public synchronized void guardedMethod()

 {

     if(警戒条件否定)

        return ;

       //警戒条件满足情况

     目的操作

   }
适用性:在线程访问警戒条件不成立的时候,不需要刻意执行等待的时候,不想一直等待警戒条件成立的时候,或者警戒条件只有第一次成立的时候。注意线程的start方法就是利用这种方式的,即只有第一次成立的时候才会调用,第二次调用就会出错。




本文转自 zhao_xiao_long 51CTO博客,原文链接:http://blog.51cto.com/computerdragon/1201769
相关文章
|
8天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
10天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
10天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
10天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
33 3
|
10天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
91 2
|
18天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
46 6
|
27天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
27天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
50 3
|
2月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
40 4
|
7月前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
73 4