5月8日学习记录

Java并发编程之Object.wait()/notify()详解

等待/通知机制
一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另外一个线程。前者是生产者,后者是消费者,这种模式隔离了“做什么”(What)和“怎么做”(How),在功能层面上实现了解耦,体系结构上具备良好的伸缩性,在Java语言中是如何实现类似的等待/通知机制的呢?

最简单的方式就是让消费者不断地循环检查变量是否符合预期,如下面代码所示,在while循环中设置不满足的条件,如果条件满足就退出循环,从而完成消费者的工作。

通过上述的分析,可以发现,wait()方法会释放所占有的ObjectMonitor对象,而notify()和notifyAll()并不会释放所占有的ObjectMonitor对象,它们的主要工作是将相应的线程从_WaitSet转移到_EntryList中,然后等待竞争获取锁。

其实真正释放ObjectMonitor对象的时间点是在执行monitorexit指令,一旦释放ObjectMonitor对象后,_EntryList中ObjectWaiter节点所保存的线程就可以竞争ObjectMonitor对象进行加锁操作了。

通过Callable和Future创建可获取执行结果的线程
  • 创建线程的三种方式的对比:
  1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

  2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

  • 通过Callable和Future创建线程的步骤:
  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。

  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。

  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。

  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

public class TestCallable {

	public static void main(String[] args) {
		CallableTask callableTask = new CallableTask();
		
		FutureTask<Map> futureTask = new FutureTask<Map>(callableTask);
		
		Thread thread = new Thread( futureTask );
		
		thread.start();
		
		try {
			Map map = futureTask.get();
			
			System.out.println( map.get("string") );
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
	
}


class CallableTask implements Callable<Map> {

	@Override
	public Map call() throws Exception {
		System.out.println( Thread.currentThread().getName() );
		
		Map map = new HashMap<String, String>();
		
		map.put("string", "stringvalue");
		
		return map;
	}
	
}
Java Runnable与Callable区别

相同点:

两者都是接口;
两者都可用来编写多线程程序;
两者都需要调用Thread.start()启动线程;

不同点:

两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

注意点:

Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值