线程的基础

来源:互联网 发布:网络十大丑男照片 编辑:程序博客网 时间:2024/06/06 02:32

一.进城、线程、协程之间的联系。

进程就可以看做是一个应用程序,而线程是进程的执行单元,多个线程组成一个完整的进程,而协程的话就是线程的拆分,它将线程细分化,能进一步优化并发编程,暂不做细讲。

二.线程的生命周期:

①新生态:Thread t=new Thread();

②就绪:t.start();线程被启动,等待被分配给CPU的时间片,获取CPU资源

③运行:线程获取CPU资源执行run()方法;

④阻塞:由于某些阻塞事件sleep(),wait()....导致线程进入就绪状态,等待重新获取资源

⑤死亡:当线程被杀死或者run()方法运行完。

三.并发编程:

①好处:能最大限度的调度CPU资源,降低等待执行时间,提高系统的吞吐量,提升性能。

②坏处:由串行编程变成并行编程,需要开发人员考虑各种可能由于并行导致的数据不一致、死锁等问题。

四.Volatilesynchronized关键字

volatile修饰的属性,能保证内存的可见性,但是保证不了原子性。

synchronized可以锁方法,锁方法快,能保证原子性,用synchronized可以保证程序是串行执行的,它是重量级锁。

关键词:

内存的可见性——》被volatile修饰的属性,值的修改会被其他的线程看见,一旦发现值被修改了,那么其他线程就会将本地工作内存地址废弃,然后重新从CPU的主内存中load属性值。

原子性操作——》形如:a=a+1;a++;这种是非原子操作的,这种在并发编程中是不能保证属性值的正确性的。

 

五.并发编程常用类:

JDK的集合类:

List->Collections.synchronizedList()->Vector>CopyOnWriteArrayList;Vector的读性能不如CopyOnWriteArrayList;但是写性能比CopyOnWrite好。

Set->Collections.synchronizedSet()->CopyOnWriteArrayList

Map->ConcurrentHashMap[get无锁,put减少锁粒度]

Queue->LinkedBlockingQueue->ConcurrentLinkedQueue[无锁]

 

JDKUtil类:java.util.concurrent.atomic

AtomicIntegerAtomicLongAtomicDouble.......

 

java.util.concurrent包下

JDK线程池:Executor框架 (对多线程的管理:线程的创建和销毁都是会影响性能的)

ThreadPoolExecutor功能强大的线程池:可以根据工作需要,选择不同的线程池

如:newFixedThreadPool()方法:返回一个固定线程数量的线程池。任务提交到线程池,如果有空余的线程,就立刻执行,如果没有就暂时放到等待队列,等待执行。

newSingleThreadPool()方法,返回只有一个线程的线程池,待线程空闲,按照先进先出的顺序执行。

newCacheThreadPool()方法:返回一个可根据实际情况调整线程数的线程池。优先使用空闲的可复用的线程,如果请求量超过了可用的线程,那么就会创建新的线程执行任务。

newScheduledThreadPool方法:返回一个ScheduledExecutorService对象,可以指定线程数量。主要用于在给定时间或者给定周期定时执行一些功能任务。

可以自定义线程池只要继承ThreadPoolExeutor,也可以对线程池做一些拓展,它自带了beforeExecuteafterExecute方法,可以用于一些信息的记录以及线程池运行状态的跟踪。

六.有锁优化

①在多线程的环境中,我们要尽量避免使用全局变量,应该使用局部变量。全局变量在多线程中是共享的,很容易导致数据不一致问题。

SynchronizedReentrantLock重复锁的使用:

Synchronized锁在JDK1.6之前性能是不如Lock的,在JDK1.6之后,synchronized的性能和lock可忽略不计了。Syn相比lock的话可控性要差,Lock支持锁等待时间、锁中断,但是syn代码可读性和维护性好。

使用建议:如果在访问数据库资源不是很慢的情况下,可以选择synchronized,如果数据库操作比较频繁,很容易导致超时的情况下,可以选择Lock。这样就不会导致死锁。

③锁优化

->减少持锁时间,比如用synchronized不是锁整个方法,而是锁方法体内部涉及到资源竞争的部分。

->减少锁粒度,比如ConcurrentHashMap它默认是有16个段,每个段都是一个子hashmap,添加属性、获取属性,都是只会找到对应的其中一段,然后给这一段加锁,而不是将整个hashmap锁住。

->读写锁ReadWriteLock替换独占锁:在读多写少的场合,根据功能的不同,使用读写锁分离能提高并发。

->锁分离:读写锁的延伸。根据应用程序的功能特点,将独占锁,拆分为两把锁。

ReentrantLock  take=new ReentrantLock();

Condition notEmpty= take.newCondition();

ReentrantLock  put=new ReentrantLock();

Condition  full= put.newCondition();

->锁粗化:对于同一个锁,如果总是获取同步和释放,是会影响性能的,所以我们需要减少锁的同步次数。比如for(){synchronized(object){}}synchronized(Object){for(){}}第一种synfor循环体内,一直在获取同步和释放。

->JVM的自旋锁:通过执行空循环体。线程上下文的切换是要消耗系统资源的,频繁的挂起和恢复会给系统带来极大的压力,如果线程间的切换所需要的时间比业务处理的时间长,那就不好玩了。而通过自旋这种无锁的方式就能避免切换的耗时。

七.无锁

AtomicInterger整数,AtomicLong长整形,AtomicReference普通对象等。。。。

它们都是通过CAS自旋算法实现无锁原子操作的。

八.无锁并行框架:AminoApache下的一个分支项目,提供了用于线程安全的、基于无锁算法的一些数据结构。如:LockFreeListLockFreeVector。研究表明,它们的性能比JDK提供的加锁的LinkedListvector性能好。

九.并行程序设计模式:

①:Future模式

Master-Worker模式

Guarded Suspension模式

④生产者-消费者模式

十.协程:kilim框架,自行了解。

 

1 0