JUC概述
在Java中、线程是一个绕不过去的知识点、JUC是 java.util.concurrent工具包的简称、这是一个处理线程的工具包、JDK1.5开始出现的。
一、进程和线程详解
1.1、进程与线程
- 进程:指在系统中正在进行的一个应用程序、程序一旦运行就是进程、进程资源分配的最小单位。
- 线程:系统分配处理器时间资源的基本单位、或者说进程之内独立执行的一个单元执行流。线程-程序执行的最小单位
1.2、线程的状态
线程状态枚举类
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
1.3、Wait和Sleep方法区别
1、Sleep是Thread的静态方法、wait是Object的方法、任何对象实例都能调用。
2、Sleep不会释放锁、也不需要占用锁。Wait会释放锁、当调用前提是当前线程占有锁(即代码要在Synchronized中)
3、他们都可以被Interrupted方法终端
二、JUC的结构
1、tools(工具类):又叫信号量三组工具类
1)CountDownLatch(闭锁) 是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
2)CyclicBarrier(栅栏) 之所以叫barrier,是因为是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ,并且在释放等待线程后可以重用。
3)Semaphore(信号量) 是一个计数信号量,它的本质是一个“共享锁“。信号量维护了一个信号量许可集。线程可以通过调用 acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。
2、executor(执行者):
是Java里面线程池的顶级接口,但它只是一个执行线程的工具,真正的线程池接口是ExecutorService,里面包含的类有:
1)ScheduledExecutorService 解决那些需要任务重复执行的问题
2)ScheduledThreadPoolExecutor 周期性任务调度的类实现
3、 atomic(原子性包):是JDK提供的一组原子操作类
包含有AtomicBoolean、AtomicInteger、AtomicIntegerArray等原子变量类,他们的实现原理大多是持有它们各自的对应的类型变量value,而且被volatile关键字修饰了。这样来保证每次一个线程要使用它都会拿到最新的值。
4、locks(锁包):
是JDK提供的锁机制,相比synchronized关键字来进行同步锁,功能更加强大,它为锁提供了一个框架,该框架允许更灵活地使用锁包含的实现类有:
1)ReentrantLock 它是独占锁,是指只能被独自占领,即同一个时间点只能被一个线程锁获取到的锁。
2)ReentrantReadWriteLock 它包括子类ReadLock和WriteLock。ReadLock是共享锁,而WriteLock是独占锁。
3)LockSupport 它具备阻塞线程和解除阻塞线程的功能,并且不会引发死锁。
5、collections(集合类):
主要是提供线程安全的集合, 比如:
1)ArrayList对应的高并发类是CopyOnWriteArrayList,
2)HashSet对应的高并发类是 CopyOnWriteArraySet,
3)HashMap对应的高并发类是ConcurrentHashMap等等
三、Lock锁(重点)
随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
/**
* @ClassName: LSaleTicket
* @Author: VV
* @Version: 1.0.0
* @Description: TODO
* @MyEmail: vv1213418894@163.com
* @CreateTime: 2022-09-12 16:48:39
*/
class LTicket{
// 票数量
private int number = 30;
// 创建可重入锁
private final ReentrantLock lock = new ReentrantLock();
// 卖票方法
public void sale(){
try {
lock.lock();
if(number > 0){
System.out.println(Thread.currentThread().getName() + ": 卖出" + (number--) + " 剩余 " + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
}
public class LSaleTicket {
public static void main(String[] args) {
LTicket ticket = new LTicket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"AA").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"BB").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"CC").start();
}
}
Lock和Synchronized区别
- Lock是一个接口、而Synchronized是Java中的关键字、Synchronized是内置语言实现。
- Synchronized在发生异常时、会自动释放线程占有的锁、因此不会导致死锁现象发生、而Lock在发生异常时、如果没有主动通过unLock()去释放锁、则很可能造成死锁现象、因此使用Lock时需要在finally块中释放锁。
- Lock可以让等待锁的线程响应中断、而synchronized却不行、使用synchronized时、等待的线程会一直等待下去、不能够响应中断。
- 通过lock可以知道有没有成功获取锁、而synchronized无法办到
- Lock可以提高多个线程进行读操作效率
四、集合的线程不安全
集合线程不安全演示
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.next(ArrayList.java:861)
at java.util.AbstractCollection.toString(AbstractCollection.java:461)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at com.atqianfen.thread.ThreadDemo02.lambda$main$0(ThreadDemo02.java:24)
at java.lang.Thread.run(Thread.java:748)
源码
/**
* Appends the specified element to the end of this list (optional
* operation).
*
* <p>Lists that support this operation may place limitations on what
* elements may be added to this list. In particular, some
* lists will refuse to add null elements, and others will impose
* restrictions on the type of elements that may be added. List
* classes should clearly specify in their documentation any restrictions
* on what elements may be added.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
* @throws UnsupportedOperationException if the <tt>add</tt> operation
* is not supported by this list
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this list
* @throws NullPointerException if the specified element is null and this
* list does not permit null elements
* @throws IllegalArgumentException if some property of this element
* prevents it from being added to this list
*/
boolean add(E e);