创建线程的三种方式
1、继承Thread类
编写一个类MyThread,继承Thread,重写run方法。
调用:创建一个MyThread对象,调用start方法
2、实现Runnable接口
编写一个类MyThread,实现Runnable接口,重写run方法。
调用:创建一个MyThread对象,开启一个Thread对象,将MyThread分配给它,调用Thread对象的start方法。
3、Callable接口
有返回值,可以抛出异常,方法不同 call()
有缓存(多个线程操作同一个FutureTask,只会执行一次?),返回结果可能需要等待,会阻塞
线程的状态
JUC
synchronized 和 Lock 的区别
1、synchronized 是java内置关键字,Lock 是java的一个类
2、synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
3、synchronized 会自动释放锁,Lock 必须手动释放锁,如果不释放锁,死锁!
4、Synchronized 线程1(获得锁,阻塞),线程2(等待,一直等待);Lock锁就不一定会等待下去!
5、Synchronized 可重入锁,不可以中断的(是指线程2在等待线程1释放锁的过程中不可中断,并不是说synchronized方法不可中断),非公平的;Lock,可重入锁,可以判断锁,非公平或公平
6、Synchronized 适合锁少量的代码同步问题
锁是什么,如果判断锁的是谁!
虚假唤醒
线程可以在没有被通知,中断或超时的情况下唤醒 ,即所谓的虚假唤醒 。
知识点
1、Condition 可以精准的通知和唤醒线程(LockSupport实现)
2、static synchronized 锁的是Class
3、class锁和对象锁不是同一个锁,互不干涉
集合
安全的List
1、Vector #使用synchronized
2、Collections.synchronizedList #使用synchronized
3、CopyOnWriteArrayList #使用ReentrantLock
底层实现原理是数组
安全的Set
1、Collections.synchronizedSet(底层实现原理是HashMap,数组+链表)
2、CopyOnWriteArraySet(底层实现原理是CopyOnWriteArrayList.addIfAbsent,数组)
安全的Map
1、HashTable #使用synchronized
2、Collections.synchronizedMap #使用synchronized
3、ConcurrentHashMap
研究HashMap和ConcurrentHashMap底层实现原理
常用辅助类
CountDownLatch
减法计数器
coutDown:数量减一
await:等待计数器归零,然后再向下执行
只能使用一次
CyclicBarrier
加法计数器
通俗的来讲是一个屏障,可循环使用
主要方法wait
Semaphore
信号量
acquire获得信号,获得信号量的线程已达到限制,其余线程等待信号的释放
release释放信号,唤醒等待的线程?如何实现的
可以用作限流操作
ReadWriteLock
其实现类为ReentrantReadWriteLock,有readLock和writeLock
注意事项:读写锁除了保证了线程安全,还可以保证读写之间的可靠行。
1、写-写操作,只允许同时只有一个写
2、读-读操作,没有限制
3、读-写/写-读操作,只允许同时只有一个进行操作,要么读等写,要么写等读!读写互斥
4、对于ConcurrentHashMap,如果读写方法没有synchronized,读写之间没有等待!
队列
BlockingQueue
ArrayBlockingQueue可阻塞队列
FIFO队列
阻塞写入:如果队列满了则必须等待
阻塞读取:如果队列空了则必须等待
4组API:
异常是指队列满了或者队列为空
1、抛出异常
2、不抛出异常
3、阻塞等待
4、超时等待
方式 | 抛出异常 | 不抛异常,有返回值 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer() | put | offer(,,) |
移除 | remove | poll() | take | poll(,) |
获取队首 | element | peek() |
/**
* 抛出异常情况
*/
private static void test1(){
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
queue.add("a"); //返回true
queue.add("b"); //返回true
queue.add("c"); //返回true
//队列已满
//java.lang.IllegalStateException: Queue full
//queue.add("d");
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
//队列已空
//java.util.NoSuchElementException
//System.out.println(queue.remove());
}
/**
* 不抛出异常情况,有返回值
*/
private static void test2(){
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.offer("a"));
System.out.println(queue.offer("b"));
System.out.println(queue.offer("c"));
//队列已满
//不抛出异常,返回false
System.out.println(queue.offer("d"));
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
//队列已空
//不抛出异常,返回null
System.out.println(queue.poll());
}
/**
* 等待,阻塞(一直阻塞)
*/
private static void test3() throws InterruptedException {
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
//无返回值
queue.put("a");
queue.put("b");
queue.put("c");
//队列已满
//一直阻塞
//queue.put("d");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
//队列已空
//一直阻塞
System.out.println(queue.take());
}
/**
* 等待,阻塞(等待超时)
*/
private static void