什么是JUC
java.util .concurrent 工具包
线程和进程
- 进程 :运行起来的程序
- 线程: java默认有几个线程 2个 main 和GC
Java真的能够开启一个线程吗?
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();
并发和并行区别
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
}
线程的六种状态
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
wait/sleep 区别
- 来自不同的类
- wait =>Object
- sleep=> Thread
- 锁的释放
- 使用范围不同
- wait 在同步的代码块当中
- sleep 可以在任何地方加
- 是否需要捕获异常
Lock锁
-
synchronized 本质为排队 同步
-
public class LockDemo {
public static void main(String[] args) {
Monney monney = new Monney();
new Thread(()->{
for (int i = 0; i < 70; i++) {
monney.quqian();
}
},"a").start();
new Thread(()->{
for (int i = 0; i < 70; i++) {
monney.quqian();
}
},"b").start();
}
}
class Monney{
int num = 100;
public synchronized void quqian(){
if(num>0) {
System.out.println(Thread.currentThread().getName() + num-- + "取钱成功");
}
}
}
-
Lock
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCML3CjB-1646231988370)(D:\桌面\截图\image-20220221143707889.png)]
public class LockDemo {
public static void main(String[] args) {
Monney monney = new Monney();
new Thread(()->{
for (int i = 0; i < 70; i++) {
monney.quqian();
}
},"a").start();
new Thread(()->{
for (int i = 0; i < 70; i++) {
monney.quqian();
}
},"b").start();
}
}
class Monney{
int num = 100;
Lock lock = new ReentrantLock();
public void quqian(){
lock.lock();
if(num>0) {
System.out.println(Thread.currentThread().getName() + num-- + "取钱成功");
}
lock.unlock();
}
}
synchronized 和Lock 区别
- synchronized 是内置的java关键字,Lock是一个java接口
- synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁
- synchronized 会自动释放锁,lock必须要手动释放锁!如果不是释放就会死锁
- synchronized 线程1(获得锁并且阻塞) 线程2 会一直等待下去; 二Lock锁不会一直等待下去 lock.tryLock() 方法会去尝试获取锁
- synchronized 可重入锁,不可中断的,非公平;Lock,可重入锁,可以 判断锁,非公平(可以自己设置)
- synchronized适合锁少量的代码同步问题, Lock适合锁大量的代码
公平锁和非公平锁
Condition
- Condition可以精准的通知和唤醒线程 不再是线程去争抢CPU
public class ConditionDemo {
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1;
public void printA(){
lock.lock();
try {
while(number!=1){
condition1.await();
}
System.out.println("AAAAAAAAA");
condition2.signal();
}catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while(number!=2){
condition2.await();
}
System.out.println("BBBBBBBBB");
condition3.signal();
}catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while(number!=1){
condition3.await();
}
System.out.println("CCCCCCC");
condition1.signal();
}catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
- synchronized 锁的对象是方法的调用者
- synchronized 如果加了static 锁的就是编译过的.class模板
List如何保证安全
以下方法会报错
java.util.ConcurrentModificationException 并发修改异常错误
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for(int i =0;i<10;i++){
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
}).start();
}
}
用concurrent包下的实现可以避免异常
- 原理: CopyOnWrite写入时复制 计算机程序设计领域的优化策略
- 在写入的时候避免覆盖,造成数据问题
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();
for(int i =0;i<10;i++){
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
}).start();
}
}
同理可得 CopyOnWriteArraySet<>();
map线程安全的两种实现方式 多线程下 实际开发当中经常使用
HashMap<String,String> map = new HashMap<>();
Collections.synchronizedMap(map);
Map<String,String> map = new ConcurrentHashMap<>();
|