并行针对进程,是多个进程同时执行.
并发针对线程,是多个线程不停的切换执行,看起来像同时执行.
实现方式:
- 实现Runnable接口,重写run()方法;
推荐,优点:资源共享,避免单继承限制,避免线程池不能放入Thread类问题. - 继承Thread类,重写run()方法;
- 实现Callable接口,并与Future、ExecutorService结合使用.
状态:
- 新建状态(New):New一个线程对象.
- 就绪状态(Runnable):线程对象调用start()方法后.
- 运行状态(Running):获取到CPU资源,执行run()方法.
- 阻塞状态(Blocked):失去CPU资源.
- 一般阻塞:调用sleep()方法或其他线程join();
sleep()结束或join()的线程结束,会重新进入就绪状态.
sleep不会释放同步锁. - 同步阻塞:获取同步锁失败;
获取同步锁成功后进入就绪状态.
同步锁池是顺序执行,先到先得. - 等待阻塞:调用wait()方法;
再调用notify()方法或notifyAll()方法进入同步阻塞.
wait会释放同步锁.
调用notify()方法不一定会唤醒到需要的线程对象,它是随机唤醒一个在对象锁上wait的线程.
wait(),notify(),notifyAll()只能在synchronized修饰中调用.
- 死亡状态(Dead):run()结束或异常退出.
控制:
t.start():调用线程进入就绪状态.
Thread.yield():当前线程释放CPU资源,回到就绪状态.
Thread.sleep(long millis):当前线程休眠对应时间,进入一般阻塞,sleep时间结束回到就绪状态,不会释放同步锁.
t.join():强制执行调用线程,当前线程进入一般阻塞,强制执行线程结束或终止,当前线程回到就绪状态.
t.join(long millis):强制执行调用线程,当前线程进入一般阻塞,强制执行线程结束或终止或超时,当前线程回到就绪状态,如超时,调用线程进入等待阻塞.
o.wait():当前线程进入等待阻塞,会释放同步锁(锁对象o).只能在synchronized修饰中调用.
o.wait(long millis):相当于wait()对应时间结束后直接notify().
o.notify():随机唤醒一个在对应对象锁(锁对象o)上wait()的一个线程,进入同步阻塞.只能在synchronized修饰中调用.
o.notifyAll():唤醒所有在对应对象锁(锁对象o)上wait()的线程,进入同步阻塞.只能在synchronized修饰中调用.
t.interrupt():标记调用线程为中断状态,当其为一般阻塞或等待阻塞状态时,立即抛出InterruptedException.
Thread.interrupted():判断当前线程的中断状态,同时清除中断标记.
t.isInterrupted():判断调用线程的中断状态,不清除中断标记.
stop()(废弃):不能保证操作原子性,造成数据不完整.
suspend()(废弃):不释放锁,容易造成死锁.
resume()(废弃)
常用方法:
Thread.currentThread():获取当前线程实例.
Thread.activeCount():获取当前进程中存活的线程数.
t.isAlive():判断调用线程是否存活.
t.setName(String name):设置调用线程名称.
t.isDaemon():判断调用线程是否是守护线程.
t.setDaemon(boolean on):设置调用线程是否为守护线程.
t.setPriority(int newPriority):设置调用线程优先级.
t.getPriority():获取调用线程优先级.
同步:
1.synchronized关键字:
被synchronized修饰的代码具有可见性和原子性.synchronized是公平锁,悲观锁.
1.synchronized修饰块:
synchronized(object){
}
作用域:
object为同步锁对象,即作用域.当没有明确的object作为锁,只是为了让一段代码同步,推荐用lock(private byte[] lock=new byte[0];)作为锁对象,最为节省资源.
当object为this时,作用域为当前类的实例.
当object为Object.class(Object为当前类)时,作用域为当前类的所有实例.
2.synchronized修饰方法:
public (static) void synchronized method(){
}
作用域:
当修饰非静态方法时,作用域为当前实例.相当于锁对象为this的同步块.
当修饰静态方法时,作用域为当前类的所有实例.相当于锁对象为Object.class(Object为当前类)的同步块.
与ReentrantLock相比更为便捷.
2.ReentrantLock(重入锁):
可重复申请的锁,申请锁X次,释放锁也要X次.
公平锁与非公平锁:
非公平锁:
ReentrantLock lock=new ReentrantLock(false);
抢锁机制,先申请不一定先获得.
ReentrantLock默认构造方法为非公平锁.
公平锁:
ReentrantLock lock=new ReentrantLock(true);
顺序执行,先申请先获得.
申请锁方法:
lock.lock():申请锁,失败就等待锁.
使用方式:
ReentrantLock lock=new ReentrantLock();
public void method(){
lock.lock();
try{
}finally{
lock.unlock();
}
}
lock.tryLock():尝试申请锁,成功返回true,失败返回false,不等待锁.
lock.tryLock(long timeout,TimeUnit unit):限定时间内尝试申请锁,成功返回true,失败就等待锁对应时间,超时返回false.
使用方式:
ReentrantLock lock=new ReentrantLock();
public void method(){
if(lock.tryLock()){//lock.tryLock(3,TimeUnit.SECONDS);
}
try{
}finally{
if(lock.isHeldByCurrentThread()){//判断当前线程是否持有该锁
lock.unlock();
}
}
}
lock.lockInterruptibly():申请可中断锁,类似lock(),但是等待锁时可以被中断(通过t.interrupt()),中断时抛出InterruptedException.
常用方法:
isFair():是否是公平锁.
isLocked():是否被线程获取.
hasQueuedThreads():是否有线程在等待此锁.
hasQueuedThread(Thread t):线程t是否在等待此锁.
getQueueLength():等待此锁的线程数.
hasWaiters(Condition c):是否有线程在c上await().
getWaitQueueLength(Condition c):在c上await()的线程数.
isHeldByCurrentThread():当前线程是否获取到锁.
getHoldCount():当前线程申请锁次数,即此线程执行lock()次数.
Condition:
ReentrantLock提供了类似于synchronized的wait()和notify()的机制,通过创建Condition对象来实现.
Condition condition=lock.newCondition();
控制:
condition.await():等效于于wait().
condition.signal():类似于notify(),区别在于其是唤醒在对应condition对象await()的线程,不是随机唤醒一个.
condition.signalAll():等效于于notifyAll().
和synchronized类似,使用以上方法必须在获取到锁之后.
扩展:
ReentrantReadWriteLock(读写锁):
读写锁和重入锁类似,用法基本一致,区别在于读写锁分两种状态,读锁和写锁,读读共享,读写互斥,写写互斥.而重入锁完全互斥.
使用方式:
ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
public void read(){
lock.readLock.lock();
try{
}finally{
lock.readLock.unlock();
}
}
public void write(){
lock.writeLock.lock();
try{
}finally{
lock.writeLock.unlock();
}
}
与ReentrantLock相比效率更高.
通常在finally中释放锁,可以有效避免死锁.
与synchronized相比操作性更好.
3.Atomic类(原子操作类):
通过volatile和CAS在硬件层面实现线程安全和同步,Atomic类是乐观锁(乐观锁其实是不加锁的).
分类:
基本类:
AtomicInteger:
常用方法:
set(int newValue)
get()
getAndSet(int newValue):设置为新值,返回旧值.
compareAndSet(int expect, int update):如果当前值为expect,则设置新值为update,返回是否成功.
addAndGet(int delta):当前值+delta,返回新值.
incrementAndGet():当前值+1,返回新值.
decrementAndGet():当前值-1,返回新值.
getAndAdd(int delta):当前值+delta,返回旧值.
getAndIncrement():当前值+1,返回旧值.
getAndDecrement():当前值-1,返回旧值.
AtomicLong:
常用方法同AtomicInteger.
AtomicBoolean:
常用方法:
set(boolean newValue)
get()
getAndSet(boolean newValue)
compareAndSet(boolean expect, boolean update)
引用类:
AtomicReference<V>:
常用方法,方法解释参考AtomicInteger:
set(V newValue)
get()
getAndSet(V newValue)
compareAndSet(V expect, V update)
AtomicMarkableReference:带标记位的原子引用类.
AtomicStampedReference:带版本号的原子引用类.
数组类:
AtomicIntegerArray:
常用方法:
length():返回数组长度.
set(int i, int newValue):将数组下标为i的元素设置为newValue.
get(int i):返回数组下标为i的元素.
getAndSet(int i, int newValue):将数组下标为i的元素设置为新值,返回旧值.
compareAndSet(int i, int expect, int update):如果数组下标为i的元素当前值为expect,则设置新值为update,返回是否成功.
addAndGet(int i, int delta):将数组下标为i的元素当前值+delta,返回新值.
incrementAndGet(int i):将数组下标为i的元素当前值+1,返回新值.
decrementAndGet(int i):将数组下标为i的元素当前值-1,返回新值.
getAndAdd(int i, int delta):将数组下标为i的元素当前值+delta,返回旧值.
getAndIncrement(int i):将数组下标为i的元素当前值+1,返回旧值.
getAndDecrement(int i):将数组下标为i的元素当前值-1,返回旧值.
AtomicLongArray:
同AtomicIntegerArray.
AtomicReferenceArray<E>:
常用方法:
length()
set(int i, E newValue)
get(int i)
getAndSet(int i, E newValue)
compareAndSet(int i, E expect, E update)
更新器类:
更新器类对应的字段必须使用"public volatile"修饰.
AtomicIntegerFieldUpdater<T>:
常用方法:
newUpdater(Class<U> tclass, String fieldName):为具有给定字段的对象创建并返回更新器,对象类型为tclass,字段名为fieldName.
set(T obj, int newValue):将obj对象对应字段设置为newValue.
get(T obj):返回obj对象对应字段.
getAndSet(T obj, int newValue):将obj对象对应字段设置为新值,返回旧值.
compareAndSet(T obj, int expect, int update):如果obj对象对应字段当前值为expect,则设置新值为update,返回是否成功.
addAndGet(T obj, int delta):将obj对象对应字段当前值+delta,返回新值.
incrementAndGet(T obj):将obj对象对应字段当前值+1,返回新值.
decrementAndGet(T obj):将obj对象对应字段当前值-1,返回新值.
getAndAdd(T obj, int delta):将obj对象对应字段当前值+delta,返回旧值.
getAndIncrement(T obj):将obj对象对应字段当前值+1,返回旧值.
getAndDecrement(T obj):将obj对象对应字段当前值-1,返回旧值.
使用方式:
public TestAtomicIntegerFieldUpdater{
public static AtomicIntegerFieldUpdater<User> aifu=AtomicIntegerFieldUpdater.newUpdater(User.class,"age");
public static void main(String[] args) {
User user=new User(20);
aifu.set(user,21);
aifu.incrementAndGet(user);
aifu.addAndGet(user,2);
aifu.compareAndSet(user,24,27);
System.out.println(aifu.get(user));
}
static class User{
public volatile int age;
public User(int age){
this.age=age;
}
}
}
输出:
27
AtomicLongFieldUpdater<T>:
同AtomicIntegerFieldUpdater.
AtomicReferenceFieldUpdater<T,V>:
常用方法:
newUpdater(Class<U> tclass, Class<W> vclass, String fieldName):为具有给定字段的对象创建并返回更新器,对象类型为tclass,字段类型为vclass,字段名为fieldName.
set(T obj, V newValue)
get(T obj)
getAndSet(T obj, V newValue)
compareAndSet(T obj, V expect, V update)
使用方式:
public TestAtomicReferenceFieldUpdater{
public static AtomicReferenceFieldUpdater<User,String> arfu=AtomicReferenceFieldUpdater.newUpdater(User.class,String.class,"name");
public static void main(String[] args) {
User user=new User("tom");
arfu.set(user,"jack");
arfu.compareAndSet(user,"jack","sam");
System.out.println(arfu.get(user));
}
static class User{
public volatile String name;
public User(String name){
this.name=name;
}
}
}
输出:
sam
4.BlockingQueue<E>(阻塞队列):
BlockingQueue为接口,通过ReentrantLock和Condition来保证同步,主要用于生产者消费者模式.
实现类:
ArrayBlockingQueue<E>:使用方式类似于ArrayList.
LinkedBlockingQueue<E>:使用方式类似于LinkedList.
公有方法:
插入方法:
add(E e) : 添加成功返回true,失败抛IllegalStateException异常.
offer(E e) : 成功返回 true,如果此队列已满,则返回 false.
put(E e) :将元素插入此队列的尾部,如果该队列已满,则一直阻塞.
删除方法:
remove(Object o) :移除指定元素,成功返回true,失败返回false.
poll() : 获取并移除此队列的头元素,若队列为空,则返回 null.
take():获取并移除此队列头元素,若没有元素则一直阻塞.
检查方法:
element() :获取但不移除此队列的头元素,没有元素则抛异常.
peek() :获取但不移除此队列的头;若队列为空,则返回 null.
5.volatile关键字:
volatile是变量修饰符,其修饰的变量具有可见性,但不能保证操作的原子性,所以不能保证并发的正确性.
可见性:是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.
6.ThreadLocal<T>(线程局部变量):
ThreadLocal为使用该变量的线程提供一个独立的副本,在各个线程互不影响,因此保证了线程安全,但并不保证同步.
常用方法:
initialValue():设置当前线程该变量副本初始值,重写时使用.
get():获取当前线程该变量副本.
set(T value):设置当前线程该变量副本.
remove():删除当前线程该变量副本,用于该变量不再使用后,避免内存泄漏.
使用方式:
public class TestThreadLocl{
public static ThreadLocal<Integer> value=new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) throws InterruptedException {
System.out.println("main:"+value.get());
value.set(1);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread:"+value.get());
value.set(2);
System.out.println("thread:"+value.get());
}
}).start();
Thread.sleep(1000);
System.out.println("main:"+value.get());
}
}
输出:
main:0
thread:0
thread:2
main:1
参考博客:
https://blog.csdn.net/evankaka/article/details/44153709#t1
https://blog.csdn.net/evankaka/article/details/44153709#t1
https://blog.csdn.net/sinat_36042530/article/details/52565296
https://blog.csdn.net/i_am_kop/article/details/80958856
https://www.cnblogs.com/chengxiao/p/6528109.html#t1
https://blog.csdn.net/woshiluoye9/article/details/72544764
https://blog.csdn.net/javazejian/article/details/77410889?locationNum=1&fps=1