首页 > 编程语言 >JUC并发编程

JUC并发编程

时间:2022-11-17 22:57:43浏览次数:38  
标签:JUC Thread lock 编程 number 并发 线程 new public

1 并发:

多个线程操作同一个资源 在cou一核的时候,多个线程模拟并发

2并行

cpu多核的时候,多个线程同时执行

3并发编程的本质:充分利用cpu的资源

4wait和sleep的区别:

wait来自object类,sleep来自thread类

wait会释放锁,sleep不会释放锁

wait只能用在同步代码块中,sleep可以用在任何地方

5 Lock锁(重点)

创建Lock锁:

class Sale1{
private int num=60;//60张票
public void saletick(){
Lock lock=new ReentrantLock();
lock.lock();
try {
if(num>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(60-num)+"票,剩余"+(num--)+"张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

java.until.concurrent.lock下面有三个接口分别为:Condition,Lock,ReadWriteLock

公平锁:十分公平,排队

非公平锁:不公平,可以插队(默认是非公平锁)

Synchronized和Lock的区别:

Synchronized是java内置的关键字,是jvm支持的,Lock是java接口

Synchronized无法判断获取锁的状态,Lock能够判断获取锁的状态

Synchronized会自动释放锁,Lock需要手动释放锁,否则会导致死锁

Synchronized可以给类,方法,代码块加锁,Lock只能给代码块加锁

Synchronized线程1(获得锁,阻塞)线程二(会一直等待),Lock锁就不一定会等待下去

Synchronized是可重入锁,非公平的,Lock是可重入锁,非公平的(可以设置为公平锁)

6生产者消费者问题(等待,业务,通知)

使用while判断解决虚假唤醒问题

Synchronized版的

public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for(int i=0;i<10;i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A线程").start();

new Thread(()->{
for(int i=0;i<10;i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B线程").start();

new Thread(()->{
for(int i=0;i<10;i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C线程").start();
new Thread(()->{
for(int i=0;i<10;i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D线程").start();
}
}
class Data{
private int number=0;
public synchronized void increment() throws InterruptedException {
while (number!=0){
this.wait(); //等待
}
number++; //业务
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll(); //通知其他线程,我已做完
}

public synchronized void decrement() throws InterruptedException {
while (number==0){
this.wait(); //等待
}
number--; //业务
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll(); //通知其他线程,我已做完
}
}

因为有两个生产者A和C线程,在减1以后会唤醒所有线程,所以两个生产者被唤醒后会执行if语句后的加1

 

Lock版的:

class Data{
private int number=0;
Lock lock=new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
lock.lock();
try {
while (number!=0){
condition.await(); //等待
}
number++; //业务
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll(); //通知其他线程,我已做完,唤醒全部
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}

public synchronized void decrement() throws InterruptedException {
lock.lock();
try {
while (number==0){
condition.await(); //等待
}
number--; //业务
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll(); //通知其他线程,我已做完
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

 

 

condition可以精准的通知和唤醒线程:

public class B {

public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(()->{
for(int i=1;i<=5;i++)data3.printA();
},"A线程").start();

new Thread(()->{
for(int i=1;i<=5;i++)data3.printB();
},"B线程").start();
new Thread(()->{
for(int i=1;i<=5;i++)data3.printC();
},"C线程").start();
}
}
class Data3{
private Lock lock=new ReentrantLock();
private Condition condition1=lock.newCondition();
private Condition condition2=lock.newCondition();
private Condition condition3=lock.newCondition();
private int num=1; //1A 2B 3C
public void printA(){
lock.lock();
try {
while(num!=1){
condition1.await(); //等待
}
System.out.println(Thread.currentThread().getName()+"=>AAAAAAAAA");
num=2;
condition2.signal(); //唤醒指定的B
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while(num!=2){
condition2.await(); //等待
}
System.out.println(Thread.currentThread().getName()+"=>AAAAAAAAA");
num=3;
condition3.signal(); //唤醒指定的C
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while(num!=3){
condition3.await(); //等待
}
System.out.println(Thread.currentThread().getName()+"=>AAAAAAAAA");
num=1;
condition1.signal(); //唤醒指定的A
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

List在多线程下是不安全的,多个线程添加元素会出现并发修改异常(Set也一样)

解决方案有三个:

List<String> list1=new Vector<>();
List<String> lsit2= Collections.synchronizedList(new ArrayList<>());
List<String> list3=new CopyOnWriteArrayList<>();
//写入时复制,在写入的时候避免覆盖,读写分离 比vector 效率高的多

HashMap也是不安全的:解决方式L:

Map<Object, Object> map1 = Collections.synchronizedMap(new HashMap<>());
Map<Object, Object> map2 = new ConcurrentHashMap<>();

Callable接口:

public class Demp {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread myThread = new MyThread();
//适配类
FutureTask futureTask = new FutureTask<Integer>(myThread);
new Thread(futureTask).start();
Object o = futureTask.get(); //获取callable中的返回结果 会产生阻塞,把它放到最后,或者采用异步通信来处理
System.out.println(o);
}
}
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return 1024;
}
}

细节:1有缓存 2结果可能需要等待,会产生阻塞

 

AQS组件L:三大辅助类:

1countdownlatch:比如说一个班级有6个学生,这个的作用就是等待这6个学生都走完了以后,在锁门,也就是刚开始有一个计数器,执行countdown的话,计数器会减1,

只有当计数器归0的时候,await方法会等待计数器归0.线程才会向下进行

2 cyclicbarrier:是一个加法计数器,初始化的时候有两个参数,比如说我想等待7个线程执行完了以后,我再执行新的线程,await等待到了以后,就会执行新的线程

3 semaphore:相当于停车位,比如最多设置3个线程可以进来,当有6个线程的时候,先进来前三个,等他们出去了,再进来后三个acquriy和release(可以并发限流)

 读写锁:readwritelock:读读共存,读写互斥,写写互斥

 

阻塞队列:blockingqueue:写入:队列满的时候会阻塞,必须等待  读取:队列空的时候会阻塞,必须等待

四组api:添加移除元素:

 

 SynchroousQueue:进去一个元素,必须等这个元素取出来后,才能接着往里放下一个元素  put和take操作

 

 

线程池的好处:线程复用,可以控制最大并发数,管理线程

线程池三大方法,七大参数,四种拒绝策略;

三大方法:

Executors.newSingleThreadExecutor();//单个线程
Executors.newFixedThreadPool(5);//固定大小
Executors.newCachedThreadPool();//可伸缩
上面三个方法会导致oom

七大参数

 

 

四大拒绝策略:

abortpolicy:线程任务丢弃报错

discordpolicy:线程丢弃不报错

discordoldsetpolicy:将队列首任务丢弃,将最新的线程任务重新加入队列执行

callerrunspolicy:线程池之外的线程直接调用run方法

标签:JUC,Thread,lock,编程,number,并发,线程,new,public
From: https://www.cnblogs.com/zhangtaibing/p/16884822.html

相关文章