线程
线程的状态
常见方法
休眠:public static void sleep(long millis)
当前线程休眠时间
放弃:public static void yield()
当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
结合:public final void join()
允许其他线程加入加入当前线程,阻塞正在运行的线程
线程的状态(等待)
线程安全
线程不安全
当线程并发访问临界资源时,如果被破坏原子造作,可能会造成数据不一致。
临界资源:共享资源(同一对象)。一次仅允许一个线程使用,才可保证其正确性
原子操作:不可分隔的多步操作,被分为
!多线程在操作一个文件或对象,变量就会产生线程安全问题,解决办法就是加锁
线程的状态(阻塞)
线程同步(1)使用synchronized
线程同步(2)synchronized返回值
同步规则:只有在调用发包含同步代码块的方法,或者同步方法使,才需要对象的锁标记,如调用不包含同步·代码的方法,或普通方法使,则不需要所标记,可直接调用。
已知jdk中线程安全的类
StringBuffer,Vector,Hashtable,以上类中的公开方法,均为synchronized修饰的同步方法
线程通信
等待
Public final void wait()
Public fianl void wait(long timeout)
必须在对object加锁的同步代码块中,在一个线程池中,调用obj.wait()时,此线程会释放其拥有的所有标记。同时此线程阻塞在o的等待队列中,释放锁,进入等待队列。
通知
Public final void notify()
Public final void notifyAll()
必须在对obj加锁的同步代码块中。从obj的waiting中释放一个或全部线程。对自身没有任何影响。
高级线程
线程池
线程容器:可设定线程分配的数量上限,将预先创建的线程对象存入线程池中,并重用线程池中的线程对象。避免频繁创建和销毁。
线程池原理:
将任务提交给线程池,由线程池分配线程,运行任务,并在当前任务结束后复用线程
获取线程池
常用的线程池接口和类(所在包java.util.concurrent):
Executor:线程池的顶级接口
ExecutorService:线程池接口,可通过submit(Runnable tsk)提交任务代码。
Executors工厂类:通过此类可以获得一个线程池。
通过newFixedThreadPool(int nThreads)获取固定数量的线程池。参数:指定线程池中线程的数量。
通过newCachedThreadPool()获得动态数量的线程池,如不够则创建新的,无上限。
Callable接口
Public interface callable<V>{ public V call() throws Exception; }
Callable具有泛型返回值、可以声明异常。
Future接口
异步接收ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值。
方法:V get()以阻塞形式等待future中的异步处理结果(call()返回值)。
Lock接口
与synchronized比较,显示定义,结构更灵活,提供更多实用性方法,功能更强大,性能更优越。
常用方法:
void lock() // 获取锁,如锁被占用,则等待
Boolean tryLock() // 尝试获取锁(成功返回frue,失败返回false,不阻塞)
Void unlock() // 释放锁,一般加锁后必须要释放锁,
重入锁
ReentrantLock:lock接口的实现类,与synchronized一样具有互斥锁功能。
读写锁
ReentrantReadWriteLock:一种支持一些多读的同步锁,读写分离可分被分配读锁,写锁,支持多次分配读锁,使多个读操作可以并发执行。
互斥规则:
写-写 :互斥,阻塞
读-写 : 互斥,读阻塞写,写堵塞读
读-读 : 不互斥,不阻塞。
在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。
ReentrantReadWriteLock
运行结果:2次写各占一秒,18次读共占1秒
线程安全的集合
CopyOnWriteArrayList
(使用与ArrayList一样):读不锁,写有锁,读写之间不阻塞,优于读写锁.写入时,先copy一个容器副本,再添加新元素,最后替换引用.
CopyOnWriteArraySet
底层采用CopyOnWriteArrayList实现,不同在于,使用add添加元素时会调用addIfAbsent()方法,会遍历数组,如元素存在,则不添加.
ConcurrentHashMap
(使用与hashMap一样):采用分段锁.,默认16段。
Queue
表示队列先进先出(FIFO).
offer(E e);添加元素.(到达上限后,在添加则会返回false)
poll() ;获取第一个元素并移除.(如果队列没有元素时,则返回null)
peek();获取第一个元素但不删除. (如果队列没有元素时,则返回null)
ConcurrentLinkedQueue
线程安全,可高效读写的队列,高并发下性能最好的队列.无锁,CAS比较交换算法
BlockingDeque
是Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法.适用场景:可用于解决生产者和消费者问题.
ArrayBlockingQueue:数组结构实现,有界队列.(手工固定上限)
LinkedBlockingDeque:链表结构实现,无界队列.(默认上限是Integer.MAX_VALUE)
生产者与消费者问题: