并发编程知识

List的线程安全问题

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ClassName VectorTest
 * @Author xsshuai
 * @Date 2022/3/3 3:28 PM
 **/
public class VectorTest {
    public static void main(String[] args) {
        //线程不安全
        //List<String> list = new ArrayList<>();
        //使用Vector创建线程安全List
        //List<String> list = new Vector<>();
        //调用Collections的静态方法创建线程安全List
        //List<String> list = Collections.synchronizedList(list);
        //使用CopyOnWriteArrayList创建线程安全List
        List<String> list = new CopyOnWriteArrayList<>();
        
        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();
        }
    }
}

Set的线程安全问题

import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ClassName VectorTest
 * @Author xsshuai
 * @Date 2022/3/3 3:28 PM
 **/
public class VectorTest {
    public static void main(String[] args) {
        //线程不安全
        Set<String> set = new HashSet<>();
        //使用CopyOnWriteArraySet创建线程安全set
        //Set<String> set = new CopyOnWriteArraySet<>();

        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
    }
}

Map的线程安全问题

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName VectorTest
 * @Author xsshuai
 * @Date 2022/3/3 3:28 PM
 **/
public class VectorTest {
    public static void main(String[] args) {
        //线程不安全
        //Map<String, String> map = new HashMap<>();
        //使用ConcurrentHashMap创建线程安全Map
        Map<String, String> map = new ConcurrentHashMap<>();
        for (int i = 0; i < 30; i++) {
            String key = String.valueOf(i);
            new Thread(()->{
                map.put(key, UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }
}

synchronized关键字的说明

synchronized是实现同步的基础,Java中的每一个对象都可以作为锁,具体表现为以下3种形式。
1、对于普通同步方法,锁是当前类的实例对象
2、对于静态同步方法,锁是当前类的class对象
3、对于同步代码块,锁是synchronized括号里配置的对象

公平锁和非公平锁

非公平锁:可能有的线程没有机会运行,出现线程“饿死”的情况,但效率高
公平锁:所有线程都有机会被执行,但是效率低

可重入锁

synchronized和Lock都是可重入锁,synchronized是隐式的,Lock是显式的,可重入锁的特点是线程一旦获得可重入锁,就可以在同步代码块中畅通执行,不需要在去获得锁。

死锁

两个或两个以上的线程执行过程中,一个线程已经持有一部分资源而等待其他线程释放另一部分资源,形成互相等待的现象,如果没有外力干涉,死锁不能自己结束。
产生死锁的原因:1、系统的资源不足2、线程的推进顺序不当3、资源分配不当
死锁演示

import java.util.concurrent.TimeUnit;

/**
 * @ClassName DeadLock
 * @Author xsshuai
 * @Date 2022/3/7 1:25 PM
 **/
public class DeadLock {

    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();
        new Thread(()-> {
            synchronized (a) {
                System.out.println("线程" + Thread.currentThread().getName() + "持有资源a,并试图换取资源b");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b) {
                    System.out.println("线程" + Thread.currentThread().getName() + "获取到资源b");
                }
            }
        }, "A").start();

        new Thread(()-> {
            synchronized (b) {
                System.out.println("线程" + Thread.currentThread().getName() + "持有资源b,并试图换取资源a");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a) {
                    System.out.println("线程" + Thread.currentThread().getName() + "获取到资源a");
                }
            }
        }, "B").start();
    }
}

死锁的发现
使用jps -l命令可以发现程序所有进程的运行情况,是否产生死锁
使用jstack 进程号 可以发现具体死锁产生的原因

并发编程辅助类

CountDownLatch减少计数
等待所有线程执行完,在进行某项操作

import java.util.concurrent.CountDownLatch;

/**
 * @ClassName CountDownLatchDemo
 * @Author xsshuai
 * @Date 2022/3/7 4:07 PM
 **/
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
            new Thread(()-> {
                System.out.println(Thread.currentThread().getName() + "号同学离开教室");
                //count计数减1
                countDownLatch.countDown();
            },String.valueOf(i)).start();
        }
        //count计数没有到0则等待
        countDownLatch.await();
        System.out.println("所有同学离开,班长锁门");
    }
}

CyclicBarrier循环栅栏
一组线程相互等待,等所有线程执行完,在执行某项操作。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @ClassName CyclicBarrierDemo
 * @Author xsshuai
 * @Date 2022/3/7 4:26 PM
 **/
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, ()->{
            System.out.println("7龙珠已集齐,神龙召唤成功,你可以许一个愿望");
        });
        for (int i = 1; i <= 7; i++) {
            new Thread(()->{
                System.out.println("恭喜你已找到" + Thread.currentThread().getName() + "星龙珠");
                try {
                	//到达屏障值执行Runnable中操作,否则一直等待
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

Semaphore信号灯,多个线程抢占有限的资源

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName SemaphoreDemo
 * @Author xsshuai
 * @Date 2022/3/7 4:53 PM
 **/
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3, true);
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                try {
                    //抢占一个车位
                    semaphore.acquire();
                    System.out.println("车辆" + Thread.currentThread().getName() + "抢占到车位");
                    //设置随机停车时间
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println("车辆" + Thread.currentThread().getName() + "---------释放车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                	//释放当前车位
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

锁的分类
乐观锁和悲观锁:
乐观锁:线程获取数据时会同时获取数据的版本号,线程提交修改数据时会将之前获取版本号和现在的版本号对比,如果版本一致,修改成功,如果版本不一致,则重新修改再提交,乐观锁可以并发执行,效率高。
悲观锁:线程获取数据时会先加锁,线程操作完其他线程才能获取并操作,悲观锁不能病发执行,效率低。
表锁和行锁
表锁:表锁会对整个表加锁,其他线程无法对整张表进行操作,表锁不会产生死锁
行锁:只对某行数据加锁,其他线程可以操作其它行数据,行锁会产生死锁
读锁和写锁
读锁:共享锁,会产生死锁
写锁:独占锁,会产生死锁

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @ClassName ReadWriteLockDemo
 * @Author xsshuai
 * @Date 2022/3/7 7:08 PM
 **/
class MyCache {
    private volatile Map<String, Object> cache = new HashMap<>();

    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void put(String key, Object value) {
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "正在写入数据 " + key);
            TimeUnit.MILLISECONDS.sleep(300);
            cache.put(key, value);
            System.out.println(Thread.currentThread().getName() + "已写入数据 " + key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public Object get(String key) {
        rwLock.readLock().lock();
        Object value = null;
        try {
            System.out.println(Thread.currentThread().getName() + "正在读数据 " + key);
            TimeUnit.MILLISECONDS.sleep(300);
            value = cache.get(key);
            System.out.println(Thread.currentThread().getName() + "读到数据 " + value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           rwLock.readLock().unlock();
        }
        return value;
    }
}
public class ReadWriteLockDemo {

    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for (int i = 1; i <= 5; i++) {
            String s = String.valueOf(i);
            new Thread(()->{
                myCache.put(s, s);
            }, "写进程" + String.valueOf(i)).start();
        }

        for (int i = 1; i <= 5; i++) {
            String s = String.valueOf(i);
            new Thread(()->{
                myCache.get(s);;
            },"读进程" + String.valueOf(i)).start();
        }
    }
}

读写锁:一个资源可以被多个读线程访问,或者可以背一个写线程访问,但是不能同时存在读写线程,读写线程是互斥的,读读线程是共享的。

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ForkJoinDemo
 * @Author xsshuai
 * @Date 2022/3/7 10:41 PM
 **/
class MyTask extends RecursiveTask<Integer> {

    private static final int VALUE = 10;
    private int begin;
    private int end;

    private int result;

    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if (end - begin <= VALUE) {
            for (int i = begin; i <= end; i++) {
                result = result + i;
            }
        }else {
            int middle = (begin + end) / 2;
            MyTask task1 = new MyTask(begin, middle);
            MyTask task2 = new MyTask(middle + 1, end);

            task1.fork();
            task2.fork();
            result = task1.join() + task2.join();
        }
        return result;
    }
}
public class ForkJoinDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyTask myTask = new MyTask(1, 100);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);
        Integer result = forkJoinTask.get();
        System.out.println(result);
        forkJoinPool.shutdown();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值