java中的多线程——线程并发库

来源:互联网 发布:c语言表达式的级别 编辑:程序博客网 时间:2024/05/22 06:44
ThreadLocal
可以实现每个线程分别拥有各自的变量。如果封装上单例类,可以实现每个线程独享一个单例。
而且有一点好处,当线程结束时,与之相关的变量会被自动gc。

java.util.concurrent.Atomic包
这个包下的类是支持线程并发操作的,可以用原子方式操作数据,包括基本数据、数组中的基本数据 、以及类中的基本数据 。比如AtomicInteger,支持用原子方式更新int值

线程池 

把任务用Runnable的run方法封装,并把这个Runnable对象扔进线程池。线程池会自动分配线程处理这个任务。但会根据线程池的不同类型,作不同地操作。
1、固定线程数量的线程池
Executors.newFixedThreadPool(3);
无空闲线程时,任务不会被处理,直到某一个线程空闲下来。
2、缓存线程池
Executors.newCachedThreadPool();
无空闲线程时, 会自动创建线程。当有线程空闲一段时间无任务做,会被回收。
3、只有一个线程的线程池
Executors.newSingleThreadExecutor();
如果线程死了,则会创建个新线程,作为替补。
4、定时执行的线程池
Executors.newScheduledThreadPool(3);
会根据参数,在某时间后执行。

Callable与Future
让并发同步。。Callable的call方法与Runnable的run方法类似,也是可多线程执行的任务,但是call方法返回的结果,这个结果可以用Future的get()方法得到。当执行到Future的get()方法时,会在参数时间内,或一直等,直到call返回结果。实现多线程的同步

Lock与Condition
Lock与Condition 也是互斥操作,比Synchronized更加面向对象,也增加代码可读性。
Lock有两个很有意思的实现类ReentrantReadWriteLock.ReadLock和 ReentrantReadWriteLock.WriteLock
它俩把锁分为读取锁和写入锁两种。
ReadLock执行lock方法时,会获取写入锁。这时如果有其他线程拿有读取锁或写入锁,则会休眠,等待其他线程都把锁释放时再获取。
WriteLock执行lock方法时,会获取读取锁。这时,如果有其他线程拿着写入锁,则会休眠,等待写入锁被释放时再获取读取锁。
可以看出,实现了写与写之间互斥,读与写之间互斥,但读与读之间不互斥。
如果用来生产者-消费者,则可以实现同时只能有一个生产者,或同时只能有一个或多个消费者。
也可以用于懒汉式单例模式的多线程同步问题。
参考代码:
import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;public class SingletonLan {     private static SingletonLan singletonLan = null;     private static ReadWriteLock rwl = new ReentrantReadWriteLock();// 获取读写锁对象     private SingletonLan() {     }     public static SingletonLan getInstance() {            rwl.readLock().lock(); // 获取读取锁            if ( singletonLan == null) {                 rwl.readLock().unlock(); // 为了获取写入锁,需要先释放读取锁                 rwl.writeLock().lock(); // 获取写入锁,这时其他线程都不能再进入                 if ( singletonLan == null) { // 再次判断,防止有线程已经进入上一级判断,从而导致多次创建对象                      singletonLan = new SingletonLan();                }                 rwl.writeLock().unlock(); // 释放写入锁                 rwl.readLock().lock(); // 重新获取读取锁           }            rwl.readLock().unlock(); // 释放读取锁            return singletonLan;     }}



Semaphore
线程的计数信号灯。可以控制并发线程的数量。个人感觉与固定数量的线程池功能类似。不同点在于,固定数量的线程池在可执行前不会创建线程,而计数信号灯是把创建的线程阻塞,只有拿到灯了才正常运行。


CyclicBarrier
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。用法:在初始化时定义最大等待的数量,在线程内使用CyclicBarrier类的await方法阻塞线程,但使用这种方法阻塞的线程数量达到定义的最大等待的数量时,所有阻塞的线程会同时恢复运行。

CountDownLatch
同样是一个同步辅助类,可以让一个线程控制多个线程,也可以让多个线程控制一个线程。用法:在构造CountDownLatch对象时,初始化计数器,在一个或多个线程内使用这个对象的await方法开始等待,在其他线程内调用这个对象的countDown方法使计数器减1,当计数器为零时,所有等待的线程会恢复运行。

Exchanger
用于实现线程间的数据交换。当一个线程到达交换点后会被阻塞,等待另一个线程进入交换点,当另一个线程进行交换点后,两个线程会开始交换数据,并恢复执行

BlockingQueue
阻塞队列,可以用put和take对队列进行操作,在put时如果队列满的,则会阻塞线程,直到有空间put成功后恢复。take时如果队列是空的,也会阻塞线程,直到队列有元素,take成功后恢复。

并发集合

ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet

专用于多线程时的集合,是线程安全的。


总结:jdk5.0开始提供了线程并发库,可以针对多线程编程很方便地做一起操作,实现有意思的功能。这就像世上出了一款专治某个疑难杂症的特效药,而作为医生,就是第一时间知道对要用这种药,去解决之前不容易的这个病。
0 0
原创粉丝点击