JUC随笔


并发

并行

wait

sleep

管程

用户线程

守护进程

Lock接口

java中的sync关键字 同步锁

多线程编程的步骤:

1、创建一个资源类,在资源类创建属性和操作方法

空调资源类,空调有操作(制冷,制热) 追求高内聚,低耦合

2、在资源类的操作方法上

判断、干活、通知

3、创建多个线程、调用资源类和操作方法

4、防止虚假唤醒问题,判断在放在while()中

例子:3个售票员 卖出30张票

票是资源,票的数量是属性,卖票的方法

售票员就是3个线程

创建线程的方式:

继承Thread类、实现Runnalbe接口(经常用)、使用Callable接口、线程池

Callable接口:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Author: suny
 * @Date: 2021/09/03 上午11:59
 * @Description:
 */
public class callableTest {
    public static void main(String[] args) {

        FutureTask<Integer> futureTask1 = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName() + "come in callable");
            return 1024;
        });

        new Thread(futureTask1,"aa").start();
        try {
            System.out.println(futureTask1.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

例子:

两个线程 ,实现对一个初始值0的变量 ,一个对其值+1,另一个对其值-1

可重入锁:厕所(每个人进去都会上锁,粗来解锁) Lock接口

Lock的操作更广,Lock不是java语言内置的

Lock和synchronized的区别:

JUC3大辅助类:

减少计数CountDownLatch(6个同学都离开后班长锁门)

import java.util.concurrent.CountDownLatch;

/**
 * @Author: suny
 * @Date: 2021/09/05 下午9:01
 * @Description: 减少计数CyclicBarrier
 */
public class CountDownLatchTest {

    //有六个同学陆续离开教室后,班长锁门
    public static void main(String[] args) throws InterruptedException {

        //创建CountDownLatch对象,设置初始值
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "离开了教室");
            },String.valueOf(i)).start();
            countDownLatch.countDown();
            System.out.println(countDownLatch.getCount());
        }


        countDownLatch.await();
        System.out.println(Thread.currentThread().getName() + "班长锁门了");
    }
}

一个或者多个线程调用await方法 让线程阻塞,其他线程

循环栅栏 (集齐7颗龙珠召唤神龙)

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

/**
 * @Author: suny
 * @Date: 2021/09/05 下午9:15
 * @Description: 收集全7颗龙珠可以召唤神龙
 */

public class CyclicBarrierTest {


    private static final int NUMBER = 7;

    public static void main(String[] args) {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER,() -> {
            System.out.println("集齐龙珠召唤神龙");
        });

        for (int i = 1; i < 8; i++) {
            new Thread(() ->{

                try {

                    try {
                        System.out.println(Thread.currentThread().getName() + "星收集到了");
                        //等待
                        cyclicBarrier.await();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

信号灯(6辆车停在3个停车位)

/**
 * @Author: suny
 * @Date: 2021/09/05 下午9:52
 * @Description:
 *
 * 3个车位,6辆汽车
 *
 */
public class SemaphoreTest {
    public static void main(String[] args) {

        Semaphore semaphore = new Semaphore(3);

        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 (Exception 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;

/**
 * @Author: suny
 * @Date: 2021/09/05 下午10:32
 * @Description:  没有写完,就开始读,会存在问题的  ----可以通过读写锁进行解决
 *    写是独占锁    读是共享锁
 */

/**
    资源类
 */
class MyCache {

    //创建map集合
    //volatile 保证可见性,禁止重排序
    private volatile Map<String,Object> map = new HashMap<>();

    //创建读写锁对象
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    //存数据

    public void putData(String key, Object value){
        //添加锁
        rwLock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "正在写操作" + key);
            //暂停一会
            TimeUnit.MICROSECONDS.sleep(300);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写操作完成" + key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //释放写锁
            rwLock.writeLock().unlock();
        }

    }


    //读数据
    public Object getData(String key){

        Object res = null;
        //添加读锁
        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "正在读操作" + key);
            //暂停一会
            TimeUnit.MICROSECONDS.sleep(300);
            res = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读操作完成" + key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //释放锁
            rwLock.readLock().unlock();
        }
        return res;
    }

}

public class ReadWriteTest {
    public static void main(String[] args) throws InterruptedException {

        MyCache myCache = new MyCache();
        //创建线程放数据
        for (int i = 1; i < 6; i++) {
            final int num = i ;
            new Thread(() -> {
                //内部类访问外部数据的时候只能访问常量(final修饰的变量)

                myCache.putData(num + "",num + "");
            },String.valueOf(i)).start();

        }
        TimeUnit.MICROSECONDS.sleep(300);
        //创建线程取数据
        for (int i = 1; i < 6; i++) {
            final int num = i ;
            new Thread(() -> {
                //内部类访问外部数据的时候只能访问常量(final修饰的变量)

                myCache.getData(num + "");
            },String.valueOf(i)).start();

        }
    }
}

文章作者: fejxc
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 fejxc !
评论
  目录