java并发编程基础 (4)

Condition与Object监视器的区别

项目 Object的监视器方法 Condition
前置条件   获得对象的锁   Lock.lock()获取锁
Lock.newCondition()获取Condition
 
调用方式   obj.wait()   condition.await()  
等待队列个数   一个   可以多个  
当前线程释放锁并进入等待状态   支持   支持  
等待状态中不响应中断   不支持   支持  
释放锁进入超时等待状态   支持   支持  
进入等待状态到将来的某个时间   不支持   支持  
唤醒等待中的一个或多个线程   支持 notify notifyAll   支持signal signalAll  

这里有一些线程的状态,可以看完后边的线程的生命周期再回过头看看

示例

一般都会将Condition对象作为成员变量。当调用await()方法后,当前线程会释放锁并在此等待,而其他线程调用Condition对象的signal()方法,通知当前线程后,当前线程才从await()方法返回,并且在返回前已经获取了锁。

实现一个有界队列,当队列为空时阻塞消费线程,当队列满时阻塞生产线程

class BoundList<T> { private LinkedList<T> list; private int size; private Lock lock = new ReentrantLock(); // 拿两个condition,一个是非空,一个是不满 private Condition notEmpty = lock.newCondition(); private Condition notFullCondition = lock.newCondition(); public BoundList(int size) { this.size = size; list = new LinkedList<>(); } public void push(T x) throws InterruptedException { lock.lock(); try { while (list.size() >= size) { // 满了就等待 notFullCondition.await(); } list.push(x); // 唤醒等待的消费者 notEmpty.signalAll(); } finally { lock.unlock(); } } public T get() throws InterruptedException { lock.lock(); try { while (list.isEmpty()) { // 空了就等 notEmpty.await(); } T x = list.poll(); // 唤醒生产者 notFullCondition.signalAll(); return x; } finally { lock.unlock(); } } } public class Demo_02_05_1_Condition { public static void main(String[] args) { BoundList<Integer> list = new BoundList<>(10); // 生产数据的线程 new Thread(() -> { for (int i = 0; i < 20; i++) { try { Thread.sleep(1000); list.push(i); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); // 消费数据的线程 new Thread(() -> { for (int i = 0; i < 20; i++) { try { System.out.println(list.get()); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } 基于BlockingQueue实现线程通信

后面会专门发文介绍BlockingQueue, 敬请关注

控制线程

参考了《疯狂java讲义》的提法,将如下内容归为控制线程的方式。

join

主线程join一个线程,那么主线程会阻塞直到join进来的线程执行完,主线程继续执行, join如果带超时时间的话,那么如果超时的话主线程也会不再等join进去的线程而继续执行.

join实际就是判断join进来的线程存活状态,如果活着就调用wait(0),如果带超时时间了的话,wait里边的时间会算出来

while (isAlive()) { wait(0); } API

public final void join() throws InterruptedException

public final synchronized void join(long millis, int nanos)

public final synchronized void join(long millis)

例子 public class Demo_02_06_1_join extends Thread { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(this.getName() + " " + i); } } public static void main(String[] args) throws InterruptedException { Demo_02_06_1_join joinThread = new Demo_02_06_1_join(); for (int i = 0; i < 100; i++) { if (i == 10) { joinThread.start(); joinThread.join(); } // 打到9就停了,然后执行joinThread这里边的代码,完事继续从10打 System.out.println(Thread.currentThread().getName()+" "+i); } } } sleep

睡觉方法,使得线程暂停一段时间,进入阻塞状态。

API

public static native void sleep(long millis) throws InterruptedException

public static void sleep(long millis, int nanos) throws InterruptedException

示例 public class Demo_02_06_2_sleep extends Thread { @Override public void run() { for (int i = 0; i < 10; i++) { if (i == 5) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } // 输出到4停止, 5秒后继续 System.out.println(this.getName() + " " + i); } } public static void main(String[] args) throws InterruptedException { Demo_02_06_2_sleep sleepThread = new Demo_02_06_2_sleep(); sleepThread.start(); } } yield

也是让线程暂停一下,但是是进入就绪状态,让系统重新开始一次新的调度过程,下一次可能运气好被yield的线程又被选中。

Thread.yield() 中断

Java中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理中断。

前面有一些方法声明了InterruptedException, 这意味者他们可以被中断,中断后把异常抛给调用方,让调用方自己处理.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdsxd.html