Java多线程

Runnable

Runnable不是线程,它只是一个接口定义了一个方法,Thread启动才是一个线程。


Thread

thread.join()方法
在主线程中调用子线程的join方法,目的是使主线程阻塞,直到子线程执行完毕才返回到主线程中。
简单理解,在主线程中调用t.join(),也就是在主线程中加入了t线程的代码,必须让t线程执行完毕之后,主线程(调用方)才能正常执行。


线程同步

线程同步一般是要解决在“单对象多线程”的情况下,控制共享变量的访问,或是控制执行步骤顺序。
控制共享变量的策略:
<ul>
     <li>将“单对象多线程”修改成“多对象多线程”;</li>
     <li>将“全局变量”降级为“局部变量”;</li>
     <li>使用ThreadLocal机制,它用于解决线程间共享变量,使用ThreadLocal声明的变量,即使在线程中属于全局变量,针对每个线程来讲,这个变量也是独立的。</li>
     <li>用final域,有锁保护的域和volatile域可以避免非同步的问题。</li>
</ul>
使用特殊域变量(volatile)实现线程同步
a.volatile关键字为域变量的访问提供了一种免锁机制,
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量

控制执行步骤
执行步骤可以使用synchronized关键字来解决
java的每个对象都有一个内置锁,当用synchronized关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则调用者就停在阻塞状态。
synchronized的原理和数据库中事务锁的原理类似。在使用过程中应该尽量缩减synchronized覆盖的范围,原因是被它覆盖的范围是串行的,效率低,并且容易产生死锁。
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。


Java5中的concurrent工具包

JavaSE5.0中新增了一个java.util.concurrent包来支持同步。
concurrent工具包中也提供了线程池,分为3类:ScheduledThreadPool、FixedThreadPool和CachedThreadPool。
有些情况下需要使用线程的返回值,可以使用Callable和CompletionService,前者返回单个线程的结果,后者返回一组线程的结果。
在concurrent工具包中,我们可以使用BlockingQueue来实现生产者-消费者模型。
使用信号量来控制线程:
JDK提供了Semaphore来实现“信号量”的功能,它提供了两个方法分别用于获取和释放信号量:acquire和release.
可以用synchronized关键字来控制单个线程中的执行步骤,要对线程池中的所有线程的执行步骤进行控制的,有两种方式,一种是使用CyclicBarrier,一种是使用CountDownLatch。
CyclicBarrier使用了类似于Object.wait的机制,它的构造函数中需要接收一个整型数字,用来说明它需要控制的线程数目,当在线程的run方法中调用它的await方法时,它会保证所有的线程都执行到这一步,才会继续执行后面的步骤。
CountDownLatch则是采取类似”倒计时计数器”的机制来控制线程池中的线程,它有CountDown和Await两个方法。
使用重入锁实现线程同步
ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
关于Lock对象和synchronized关键字的选择:
如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码。
如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁。

局部变量实现线程同步
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
ThreadLocal与同步机制
ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。
ThreadLocal采用以"空间换时间"的方法,同步机制采用以"时间换空间"的方式


Future

java1.5中Future是一个未来对象,里面保存线程处理结果,它像一个提货凭证,可以随时去提取结果。Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
在两种情况下离开Future较难处理:
<ul>
     <li>一种情况是拆分订单,比如应用收到一个批量订单,此时如果要求最快的处理订单,那么需要并发处理,并发的结果如何收集的问题如果自己编程非常繁琐,此时可以使用CompletionService解决这个问题。CompletionService将Future收集到一个队列里,可以按结果处理完成的先后顺序进队。</li>
     <li>另一种情况是如果需要并发查询一些东西(比如爬虫),并发查询只要有一个结果返回就认为查询到了,并且结束查询,这时也需要用CompletionService和Future来解决。</li>
</ul>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值