Java threads and concurrency

Threading and concurrency:
Here Insert Picture Description
the Java threads is preemptive scheduling (jvm scheduling)
parallel: Refers to two or more events occur simultaneously at the same point in time.
Concurrency: refers to two or more events occur at the same time period. Focus
single-core processor can not be parallel, concurrent can only be scheduled execution time of each time slice through the thread through the CPU.
Multi-core processors at the same point in time is concurrent execution threads together.
Process: an application running in memory, separate memory space, communication is not convenient, a process can have multiple threads.
Thread: in the same process multiple tasks. basic unit. Key
Java program has at least the main thread and a garbage collection thread
multithreading advantages: shared memory, creating a small thread costs, low share of resources, java itself to support multi-threaded (jvm support multithreading, the interior is jvm to schedule multiple threads )
to create a thread:
1. thread class inheritance, 2 implements Runnable interface (you can also use the anonymous inner class to create using only one thread) inheritance and interface methods are not the same (there are differences in operating and sharing resources)

当我们的多线程启动之后,就交给我们的jvm来调度
Start方法只能调用一次 否则报错
我们在使用多线程访问同一个资源的安全性问题时:1.同步代码块 2.同步方法 3.锁机制
同步代码块和同步方法(synchronized修饰的方法):
synchronized (this) {
//同步代码块 同时只有一个对象可以进去这个代码块 执行完后退出其他的对象才可以进入
//其中的this就是同步锁,表示当前对象
if (num > 0) {
System.out.println(Thread.currentThread().getName() + “吃了第” + num-- + “个苹果”);
}
}
Synchronized 好坏:这个也就是stringbuilder和stringbuffer的区别 stringbuffer的方法上面贴有Synchronized修饰符。提高了安全,降低了性能
1, 保证了多线程并发的同步操作,保证安全性
2, 性能低
有很多的相关都和Synchronized有关:

  1. stringbuilder和stringbuffer(安全)
  2. Arraylist和Vector(安全)
  3. Hashmap和hashtable(安全)
    我们一般用性能高但是不安全的
    我们在写单例模式时:一般推荐使用饿汉式(调用之前就直接创建类)性能高。没有线程安全性问题。我们在使用懒汉式的时候(调用时创建)会有线程安全性问题,所以推荐使用饿汉式。
    Juc包详解 :
    Here Insert Picture Description
    并发容器:一般都是采用锁分段技术,对于操作的位置进行同步操作
  4. ConcurrentHashMap(对应Hashmap)(使用分段锁):相比Hashtable进一步提高并发性。
    原理:HashMap,Hashtable与ConcurrentHashMap都是实现的哈希表数据结构,
    Hashtable是对整张哈希表进行锁定,巨大的浪费。ConcurrentHashMap和Hashtable主要区别就是围绕着锁的粒度进行区别以及如何去锁定。ConcurrentHashMap单独锁住每一个桶(segment).ConcurrentHashMap将哈希表分为16个桶(默认值),诸如get(),put(),remove()等常用操作只锁当前需要用到的桶,而size(),isEmpty()才锁定整张表。原来只能一个线程进入,现在却能同时接受16个写线程并发进入(写线程需要锁定,而读线程几乎不受限制),并发性的提升是显而易见的。 迭代时使用了不同于传统集合的快速失败迭代器(fast-fail iterator)的另一种迭代方式,称为弱一致迭代器,在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时实例化出新的数据从而不影响原有的数据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的并发性和扩展性,是性能提升的关键。
    2.CopyOnWriteArrayList(对应arraylist): 利用高并发往往是读多写少的特性,对读操作不加锁,对写操作,先复制一份新的集合,在新的集合上面修改,然后将新集合赋值 给旧的引用,并通过volatile 保证其可见性,当然写操作的锁是必不可少的了。
    3.CopyOnWriteArraySet (corresponding to HashSet): based CopyOnWriteArrayList implemented, the only difference is called when the add method is addIfAbsent CopyOnWriteArrayList which traverse the current Object array, the array has the Object as the current element, the process directly returns, if not Object is placed in the tail of an array and returns.
    1. A ConcurrentSkipListMap (corresponding to TreeMap): Skip list (jump table) is a balanced tree data structure can replace the default is ascending according to the Key value.
    2. ConcurrentSkipListSet (TreeSet): Based on internal ConcurrentSkipListMap achieve.

Concurrent queue (inherited Queue):
Common queue:
1.ArrayDeque, (array deque)
2.PriorityQueue, (priority queue)
3.linkedList (queue list)

  1. Nonblocking queue (high performance): ConcurrentLinkedQueue and ConcurrentLinkedDueue
    A) ConcurrentLinkedQueue: queues is suitable for a high concurrency scenarios, by lock-free (CAS) manner, and to achieve high performance at high concurrency thread-safe state, typically ConcurrentLinkedQueue performance is better than BlockingQueue. It is an unbounded thread-safe queue based on linked nodes. Elements of the queue to follow the FIFO principle. Is added to the first head, the tail is recently added to the queue does not allow null elements.
  2. Blocking queue (BlockingQueue): support two queues additional operations to achieve thread-safe by locking way: two operations:
    1, the queue is empty, obtain the thread elements will wait for the queue to become non-empty.
    2, when the queue is full, the thread will wait queue storage elements available.
    Blocking queue commonly used in producer and consumer scenarios.
    Blocking queue and the difference between the normal queue:
    blocking queue and common queue difference is that, when the queue is empty, the elements take acquired from the queue () operation will be blocked, or when the queue is full, add to queue elements put () operation will be blocked. Threads trying to acquire the blocking element from an empty queue will be blocked until the other thread to empty the queue insert new elements. Similarly, blocking queue is full trying to add a new element of the same thread will be blocked until the other threads queue up again become idle, such as removing one or more elements from the queue, or to completely empty the queue.
    • ArrayBlockingQueue: a structure consisting of an array bounded blocking queue.
    • LinkedBlockingQueue: a linked list of structures bounded blocking queue.
    • LinkedBlockingDeque: there is a two-way linked list structure consisting of a bounded blocking queue.

• PriorityBlockingQueue: a support prioritization of unbounded blocking queue.
• DelayQueue: using a time delay sort of unbounded blocking queue.
• LinkedTransferQueue: a linked list of structures of unbounded blocking queue.
• SynchronousQueue: a non-blocking queue storage elements.

Specific categories:

  1. SynchronousQueue no queue is a data buffer BlockingQueue, insert put its producer thread must wait for the consumer to remove the operation take, and vice versa. Allowing the housing interior can be seen as only one element. When a thread insert an element will be blocked, unless this element is consumed by another thread.
  2. Bounded queue: ArrayBlockingQueue is a blocking queue borders, its internal implementation is an array. There is meaning boundary its capacity is limited, we have to specify the size of its capacity at the time of its initialization, the capacity of the specified size once it is immutable. ArrayBlockingQueue is FIFO stored data, newly inserted object is the tail, the latest object is removed from the head.
  3. Unbounded queue: PriorityBlockingQueue is a queue no borders, its collation and java.util.PriorityQueue same. Note, PriorityBlockingQueue allowed insert null object. All objects inserted PriorityBlockingQueue java.lang.Comparable must implement the interface, queue priority is in accordance with the rules of the sort we realize this interface to define. In addition, we can get an iterator Iterator from PriorityBlockingQueue, but this does not guarantee that the iterator iterates in order of priority.
    Concurrent Tools:
  4. CountDownLatch: CountDownLatch constructor takes a parameter of type int as a counter, by calling the method countdown CountDownLatch provided, the counter may be decremented by one, he provides a method for blocking await the current thread, the counter is decremented, when the value of counter 0, then returned to normal.
    It can not be reset.
  5. CyclicBarrier: recyclable (Cyclic) barrier (Barrier). It needs to be done is to let a group of threads reach a barrier (also called synchronization point) is blocked when it until the last thread reaches the barrier, the barrier will open the door, all barriers blocked thread will continue to run. Recycling may be reset after
    the difference between 1 and 2 are: CountDownLatch counter can only be used once, and may be used CyclicBarrier counter reset () method to reset. So CyclicBarrier can handle more complex business scenarios. For example, if the calculated error occurs, you can reset the counter and let the thread again from the beginning.
    CyclicBarrier also provides other useful methods, such as getNumberWaiting ways to get the number of threads CyclicBarrier blocked. isBroken () method is used to find out if the blocked thread is interrupted.
  6. Semaphore semaphore: control the number of concurrent threads. Semaphore can control the number of threads simultaneously access a resource. The internal management of a set of permissions (a certain amount), threads need to obtain a license through the acquire () method, and release () to release license. If the license number after the maximum number of activities, then call acquire (), it will enter the waiting queue, waiting for the thread to release license has been licensed so that multiple threads can run reasonable. Semaphore mutex object can also be achieved function, and can be obtained "lock" by a thread, and then release the "locked" by another thread, which can be used in a number of occasions deadlock recovery.
  7. Exchanger 交换器:Exchanger用于实现线程间的数据交换。Exchanger提供一个同步点,在同步点上,两个线程使用exchange方法交换彼此数据。
    原子类:(底层就是volatile(可见性)和CAS(原子性)共同作用的结果)
    java.util.concurrent.atomic包下面的类;原子性变量类
    特点:多线程环境下,无锁的进行原子操作。不能绝对保证线程不被阻塞(因cpu原子指令不同,可能需要某种形式的内部锁):
    java.util.concurrent.atomic原子操作类包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。可以对基本数据、数组中的基本数据、对类中的基本数据进行操作。原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作。
    Here Insert Picture Description
    标量类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
    数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
    更新器类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
    Composite variable categories: AtomicMarkableReference, AtomicStampedReference
    be appropriate instead of lock, but the lock is more secure.
    Thread Local Storage: the task of preventing conflict on shared resources.

Lock (Interface):
Several important concepts locks:
a fair lock / non-lock fair
1. fair lock means in order to apply more than one thread lock to acquire the lock.
2. Unfair lock means multiple threads acquire locks in the order of application of the order is not locked, it is possible to apply the thread after thread priority to acquire the lock than prior application. Possible cause priority inversion or hunger.
For example: For Java ReentrantLock, the constructor specify whether the lock by lock is fair, non-default fair locks. Unfair advantage that the lock is larger than the throughput fairness lock.
For Synchronized, it is also an unfair lock. Because it is not as ReentrantLock thread scheduling is achieved by AQS (AbstractQueuedSynchronized abstract queue type synchronizer ReentrantLock, Semaphore, CountDownLatch, ReentrantReadWriteLock, FutureTask) , so and there is no way that it becomes fair locks.

Second, the reentrant lock
reentrant lock known as recursive lock means when the same thread acquires the lock of the outer layer method, the method will automatically get into the inner lock
ReentrantLock, Synchronized locks are reentrant

三、独享锁/共享锁
1.独享锁是指该锁一次只能被一个线程所持有。
2.共享锁是指该锁可被多个线程所持有。
对于ReentrantLock而言,其是独享锁。但是对于Lock的另一个实现类ReadWriteLock,其读锁是共享锁,其写锁是独享锁。
读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。
独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。
对于Synchronized而言,当然是独享锁。

四、互斥锁/读写锁
上面讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现。互斥锁在Java中的具体实现就是ReentrantLock
读写锁在Java中的具体实现就是ReadWriteLock

五、乐观锁/悲观锁
不是具体类型的锁,而是指看待并发同步的角度
悲观锁在Java中的使用,就是利用各种锁。
乐观锁在Java中的使用,是无锁编程,常常采用的是CAS算法,典型的例子就是原子类,通过CAS自旋实现原子操作的更新。

六、分段锁
分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作,目的在于细化锁粒度。

我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想,ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap(JDK7与JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。

七、偏向锁、轻量级锁、重量级锁
这三种锁是指锁的状态,并且是针对Synchronized。在Java 5通过引入锁升级的机制来实现高效Synchronized。这三种锁的状态是通过对象监视器在对象头中的字段来表明的。
偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。

八、自旋锁
在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。

九、闭锁
闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开允许所有的线程通过。当闭锁到达结束状态后,将不会再改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动指导其他活动都完成后才继续执行。CountDownLatch就是一种灵活的闭锁实现。

十、活锁
LiveLock是一种形式活跃性问题,该问题尽管不会阻塞线程,但也不能继续执行,因为线程将不断重复执行相同的操作,而且总会失败。活锁通常发送在处理事务消息的应用程序中:如果不能成功地处理某个消息,那么消息处理机制将回滚整个事务,并将它重新放到队列的开头:如果不能成功地处理某个消息,那么消息处理机制将回滚整个事务,并将它重新放到队列的开头。如果消息处理器在处理某种特定类型的消息时存在错误并导致它失败,那么每当这个消息从队列中取出并传递到存在错误的处理器时,都会发生事务回滚。由于这条消息又被放回到队列开头,因此处理器将被反复调用,并返回相同的结果。

十一、无锁
要保证现场安全,并不是一定就要进行同步,两者没有因果关系。同步只是保证共享数据争用时的正确性的手段,如果一个方法本来就不涉及共享数据,那它自然就无须任何同步措施去保证正确性,因此会有一些代码天生就是线程安全的。
无状态编程。无状态代码有一些共同的特征:不依赖于存储在对上的数据和公用的系统资源、用到的状态量都由参数中传入、不调用非无状态的方法等。可以参考Servlet。
线程本地存储。可以参考ThreadLocal
volatile
CAS
协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换

  1. synchronized的缺陷:
    如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:
      1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
    2)线程执行发生异常,此时JVM会让线程自动释放锁。
    如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程只能等待;影响效率。Lock机制就可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),还可以局部锁定,提高效率。还可以知道线程有没有成功的获取锁。Lock需要用户主动释放锁,并且在发生异常时,不会自动释放锁。(否则可能死锁),synchronized不需要。
  2. 常用类和方法:
    Lock接口中的方法:lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()(可中断)是用来获取锁的同时保持对中断的响应。
    可定时的与可轮询的锁获取模式由tryLock()实现。如果不能获得所有需要的锁,那么就会释放已经获得的锁。然后再尝试重新获取。降低活锁的可能,
    Lock lock = …;
    lock.lock();
    try{
    //处理任务
    }catch(Exception ex){

}finally{
lock.unlock(); //释放锁
}

ReentrantLock(可重入独占式锁:类):公平锁和非公平锁两种实现方式。synchronized也是可重入锁 。可重入和不可重入的概念是这样的:当一个线程获得了当前实例的锁,并进入方法A,这个线程在没有释放这把锁的时候,能否再次进入方法A呢?

可重入锁:可以再次进入方法A,就是说在释放锁前此线程可以再次进入方法A(方法A递归)。内部有一个计数器。
不可重入锁(自旋锁):不可以再次进入方法A,也就是说获得锁进入方法A是此线程在释放锁钱唯一的一次进入方法A。
ReadWriteLock(接口)维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。
最多支持 65535 个递归写入锁和 65535 个读取锁。试图超出这些限制将导致锁方法抛出 Error。有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。
ReentrantReadWriteLock是上面接口的实现类(里面还有其他的方法):
注意:如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。
LockSupport:是用来创建锁和其他同步类的基本线程阻塞原语。
LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题。
因为park() 和 unpark()有许可的存在;调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性。
Condition:的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的;而Condition是需要与"互斥锁"/"共享锁"捆绑使用的。
AbstractQueuedSynchronizer(AQS): 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架(很多的同步器都可以通过AQS简单高效的构建出来)。该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础。使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态。然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作:
java.util.concurrent.locks.AbstractQueuedSynchronizer.getState()
java.util.concurrent.locks.AbstractQueuedSynchronizer.setState(int)
java.util.concurrent.locks.AbstractQueuedSynchronizer.compareAndSetState(int, int)
子类推荐被定义为自定义同步装置的内部类,同步器自身没有实现任何同步接口,它仅仅是定义了若干acquire之类的方法来供使用。该同步器即可以作为排他模式也可以作为共享模式,当它被定义为一个排他模式时,其他线程对其的获取就被阻止,而共享模式对于多个线程获取都可以成功。
Executor框架:
New thread()的缺点:每次neYUUUw Thread()耗费性能 ,调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。 不利于扩展,比如如定时执行、定期执行、线程中断。
采用线程池的优点:重用存在的线程,减少对象创建、消亡的开销,性能佳
可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
提供定时执行、定期执行、单线程、并发数控制等功能。
executor框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。
我们发现在juc类库中,一般避免对thread对象的直接操作,而是使用executor.
Here Insert Picture Description
管理thead对象:不再显式的创建thead对象
Executor:一个接口,其定义了一个接收Runnable对象的方法executor.内部采用线程池机制。
ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法(运行,关闭,已终止三种状态),以及可跟踪一个或多个异步任务执行状况返回Future的方法.
Executors工具类:
Executors提供四种线程池,newFixedThreadPool(固定数量)、newCachedThreadPool(可据实际情况调整线程数量)、newSingleThreadExecutor(只有一个。确保任务串行执行)、newScheduledThreadPool(固定长度,且以延时或定时的方式来执行,类似于Timer)。
用来创建线程池:返回一个executorservice对象等操作。
Callable接口:
实现具有返回值的任务。Call方法。必须使用executorservice.submit()方法调用。
返回值放在future中,
Future 表示异步计算的结果。
Thread.Sleep()任务终止执行给定的时间。
优先级只表示频率,不是绝对的。
Thread.yield().让步,表示可以退让cpu资源。也不是绝对的。
后台线程:线程启动之前,调用setDaemon()方法设置。程序结束与否只和非后台线程有关。后台线程创建的线程也是后台线程。
如果普通的线程异常:会直接抛给控制台,无法捕获。我们使用:
Thread.UncaughtExceptionHandler,:当 Thread 因未捕获的异常而突然终止时,调用处理程序的接口。
ThreadPoolExecutor(线程池类):
1、线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用。
2、可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。
线程池的创建:

public ThreadPoolExecutor( int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:线程池核心线程数量
maximumPoolSize:线程池最大线程数量
keepAliverTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间
unit:存活时间的单位
workQueue:存放任务的队列
threadFactory:线程工厂:用于线程池创建线程。默认创建一个新的,非守护线程,不包含任何的配置信息。可以通过制定一个线程工厂,来配置创建的线程
handler:超出线程范围和队列容量的任务的处理程序
其中包含四种饱和策略:

  1. AbortPolicy(终止策略)默认。将抛出未检查的RejectedExcution-Exception,调用者可以捕获这个异常,然后根据需求写自己的代码,
  2. DiscardPolicy(抛弃策略) 直接抛弃该任务
  3. DiscardOldestPolicy(抛弃最旧策略) 会抛弃下一个将要执行的任务,如果是优先级队列,就抛弃优先级最高的。所以一般不和优先级队列一起使用。
  4. CallerRunPolicy(调用者运行)该策略不会抛弃任务,也不会抛出异常,而是将任务的运行回退到任务调用者,在提交任务的线程中执行该任务。
    ScheduledExecutorService接口(可安排在给定的延迟后运行或定期执行的命令。)和ScheduledThreadPoolExecutor类实现(安排在给定的延迟后运行命令,或者定期执行命令。):
    Future和Fork/Join(java7新特性):
    Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

Fork(切分)/join(合并): 可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。充分利用线程进行并行计算,并减少了线程间的竞争,
详情请看:
fork/jion详解
线程的四种状态:
新建,就绪,阻塞,死亡。
一个线程被阻塞的原因:
1.调用sleep()进入休眠.
2.调用wait()线程挂起
3.任务在等待某个输入/输出(I/O)
4,试图在某个对象上调用同步控制方法,但是对象锁不可用,因为另一个任务获取了该锁,
Thread.interrupt()中断此线程。实际上给线程设置一个中断标志,线程仍会继续运行。
Interrupted()判断是否被中断。
线程之间之间的协作:wait和notify,notifyall.方法。
死锁:任务之间相互等待的连续循环。哲学家就餐问题。

线程之间通信的方式:

  1. syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()
    如果调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。如果当前线程没有这个对象的锁就调用wait()方法,则会抛出IllegalMonitorStateException.调用某个对象的wait()方法,相当于让当前线程交出(释放)此对象的monitor,然后进入等待状态,等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁);调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
  2. ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()
    Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。
    Condition是个接口,基本的方法就是await()和signal()方法;
    Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
    调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
    Conditon中的await()对应Object的wait();
    Condition中的signal()对应Object的notify();
    Condition中的signalAll()对应Object的notifyAll()。
  3. 管道通信就是使用java.io.PipedInputStream 和java.io.PipedOutputStream。。PipedWriter和PipedReader进行通信。
  4. 锁机制和synchronized关键字的同步机制。和volatile一样,是“共享内存”式的方式
  5. 利用CyclicBarrierAPI。其实还是lock和condition机制
  6. 利用BlockingQueue;
    备注:其实对于线程间的通讯和协作我们可以分成两个大的方向:
    共享内存机制和消息通信机制
    并发模型 通信机制 同步机制 例子

共享内存 线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。 同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。 锁,synchronized,volatile
等大多数
消息传递(actor) 线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信。 由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。 管道。

锁机制(更广泛的同步操作)
Lock提供了synchronized更广泛和更强大的操作 体现面向对象(java5开始)
Lock l = …;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
进入(锁)-》执行代码-》 离开(解锁)
java5在提供lock机制的同时提供了codition接口,解决lock机制的通讯控制和互斥
现获取锁,在使用condition
总的来说:lock机制取代了synchronized机制 而condition接口就取代了其中的wait,notify,notifyall方法
多线程容易造成死锁。互相等待的情况,不同于阻塞。没有解决,只能避免。
线程的六种状态:
Wait和sleep方法:
Sleep让我们的线程放弃cpu,休眠一段时间。但是不会释放同步锁。多用于模拟网络延迟等。
但是wait方法会释放同步锁。
线程睡眠(sleep) 线程联合(join)
后台线程:我们创建的默认是前台线程。设置daemon=true是后台线程 ,在start之前设置。后台线程随着前台线程的结束就结束了。前台线程不会,
线程的优先级:高低只和获得执行机会的次数有关系,不一定谁先执行,默认都一样是5.(优先级是1-10)我们一般就使用这三个值(1,5,10)
线程的礼让:当前线程愿意让出自己的cpu资源。但是调度器可以忽略该提示,调用之后线程就绪但是可能cpu又把他重新调度回来。很少使用,
Sleep和yield的区别:
都能使当前线程放弃cpu,sleep放弃之后不考虑优先级。但是yield指挥让给优先级大于等于他的。Sleep-》计时等待 。yield->就绪。
定时器:timer类,可以定时执行某任务java.util包
线程组:我们可以在创建线程的时候就设置先线程组,没有的话。如果线程A创建了B ,没设置B就加入A所在的线程组。线程组里面的操作就是批量操作里面的线程。
ThreadLocal:本地线程变量.。
其他的一些概念:
线程封闭:数据共享需要同步操作,如果仅在单线程内访问数据,就不需要同步,这就是线程封闭。例如:局部向量和ThreadLocal类.
ThreadLocal类其实不能解决线程共享变量的问题,他就是看作保存了一个map.每一个线程都对应一个值,其他线程不能访问,就是一个保存线程本地变量。
发布一个对象是使该对象能够在当前作用域之外的代码中去使用。
任何线程都可以在不需要额外同步的情况下安全的访问不可变对象。
安全发布对象:

  1. 在静态初始化函数中初始化一个对象的引用
  2. 将对象引用保存在volatile类型或者原子类的对象中
  3. 将对象的引用类型保存在某个正确构造对象的final类型域中
  4. 将对象引用保存在锁保护的域中。
    一些共享对象的安全措施
  5. 线程封闭:
  6. 只读共享:读写锁
  7. 线程安全共享:在内部实现同步,
  8. 保护对象:只能通过持有锁来访问。
    Collections.synchronizedxxxx()。该方法实现线程安全的方式是:将他们的状态封装起来,并对每个公有的方法进行同步处理。每次只有一个线程能够访问容器的状态。
    即使是线程安全的类(hashtable vector)。在符合操作中应当注意并发修改问题。注意同步机制。
    锁是一个对象。线程去获取对象,就相当于看这个锁对象有没有被持有。
    发生死锁(两个线程都持有一个锁并且都想要获取对方的锁。)的几种情况:
    1. 锁顺序死锁:因为获得锁的顺序不同,相同就不会死锁。
    2. 动态的锁顺序死锁:转账实例。虽然加锁顺序在方法中是一致的,但是由于多线程同时操作。发生死锁。一个线程A向B转账,一个线程B向A转账。锁的顺序取决于参数的传递顺序。可以使用加时赛锁和对象的HashCode().确保加锁顺序的一致性。
    3. 在协作对象之间发生死锁:如果在持有锁时调用一个外部方法。那么将出现活跃性问题,因为外部方法可能会获取其他的锁。或者阻塞时间过长,导致其他线程无法及时获得当前被持有的锁。
    4. 资源死锁:某些任务需要等待其他任务的结果,那么很有可能产生死锁。所以有界线程池/资源池和相互依赖的任务不能一起使用。
    Synchronized:同步,线程安全,保证原子性,可见性和禁止指令重排序。互斥锁,可重入锁。非公平锁。synchronized 用的 锁 是 存在 对象头 中。
    对其中锁的讨论: 即使是两个不同的代码段,都要锁同一个对象,
  9. 修饰静态方法,锁住的是当前类的Class对象(每个类只有一个class对象): 同一个类不能同时访问。
    a) 同一类的不同对象,调用同一个静态同步方法,会等待锁释放.
    b) 同一类的不同对象,调用不同一个静态同步方法,会等待锁释放
    c) 同一对象,一个调用静态同步方法,一个调用非同步方法,不用等待锁释放.
  10. 普通的方法,锁的是当前实例。同一个对象不能同时访问。
    a) 一个对象调用同一同步方法会等待锁释放
    b) 一个对象调用不同同步方法会等待锁释放
    c) 同一对象,一个调用同步方法,另一个调用非同步方法不需要等待释放锁。
  11. 对于同步代码块。锁的是括号里面配置的对象。
    a) 当锁定的是this时。与修饰普通方法一样。锁住的是当前对象。
    b) 当锁定是其他对象,例如是string,那么在string是同一string,也就是地址相同时,才会竞争,不同时会并发执行。锁住的是其他对象,也就是其同一个对象会产生竞争。
    内置锁的实现原理:
    代码 块 同步 是 使用 monitorenter 和 monitorexit 指令 实现 的,而方法同步 是使用另外一种方式实现的 ,细节在JVM规范里并没有详细说明。但是方法的同步同样可以使用这两个指令来实现。
    在同步代码块的开始处插入指令monitorenter,结束和异常处插入monitorexit。任何 对象 都有一个monitor与之关联,当且一个monitor 被 持有 后, 它将 处于 锁定 状态。 线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权。即尝试获得对象的锁。
    Volatile:保证可见性和禁止指令重排序。不保证原子性。可见性:线程每次都是读到最新的数据。底层编译时会生成一个lock指令。
    实现原理:
    两条线程Thread-A与Threab-B同时操作主存中的一个volatile变量i时,Thread-A写了变量i,那么:
    Thread-A发出LOCK#指令
    发出的LOCK#指令锁总线(或锁缓存行),同时让Thread-B高速缓存中的缓存行内容失效
    Thread-A向主存回写最新修改的i
    Thread-B读取变量i,那么:
    Thread-B corresponding to the address found in the cache line is locked, the lock release wait, the cache coherency protocol will ensure that it reads the latest value of
    a similar memory barrier function, to ensure that the sequence of instructions. Prohibit reordering.

ThreadLocal (thread local storage):
ThreadLocal stored in the heap memory, ThreadLocalMap stored in a local buffer thread (thread spacer) of
internal ThreadLocal class maintains an internal ThreadLocalMap. WeakReferences used as keys (weak bond), in order to timely GC (avoid memory leaks). A thread corresponds to a ThreadLocalMap. get () is the current thread gets its own ThreadLocalMap, according to ThreadLocal object as a key, gets the value stored in the ThreadLocalMap. And then return.
Here Insert Picture Description
Thread a thread exists in a ThreadLocalMap, ThreadLocalMap the key corresponding to ThreadLocal, where a plurality of visible key may be stored i.e. Map (ThreadLocal). Further it corresponds Value Value stored in a ThreadLocal.

Guess you like

Origin blog.csdn.net/qq_41703795/article/details/93305855