并发编程-线程安全与解决方案

作者: 迦叶_金色的人生_荣耀而又辉煌 | 来源:发表于2020-11-25 12:19 被阅读0次

上一篇 <<<多线程基础
下一篇 >>>锁的深入化


线程安全: 当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。
做读操作是不会发生数据冲突问题。
tips:
a、局部变量不存在线程安全问题
b、只有全局变量才会存在线程安全问题

解决线程安全思路

  • 使用内置锁(synchronized)
  • 显示锁(lock)
  • CAS无锁机制
    原理都是只能让当前一个线程进行执行。代码执行完成后释放锁,然后才能让其他线程进行执行。没有获取到锁的线程,则一直会排队阻塞,整个过程是一个悲观状态。

synchronized方式

//写操作
synchronized (res) {
    //如果已经写完,没被读的话,则等待读取
    if(res.writeFlg){
        try {
            res.wait();
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    if (count == 0) {
        res.name = "老王";
        res.sex = "男";
    } else {
        res.name = "小红";
        res.sex = "女";
    }
    count = (count + 1) % 2;
    //如果写完,则唤醒读
    res.writeFlg = true;
    res.notify();
}
//读操作
synchronized (res) {
    //如果没有写,则等待先写
    if(!res.writeFlg){
        try {
            res.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println(res.name + "," + res.sex);
    //读取完后,则设置为false,唤醒写程序
    res.writeFlg = false;
    res.notify();
}

Lock锁方式,不过wait和notify需要改为await和signal

public Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
// 写操作
try {
    res.lock.lock();
    try {
        if(res.writeFlg) {
            res.condition.await();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    if (count == 0) {
        res.name = "老王";
        res.sex = "男";
    } else {
        res.name = "小红";
        res.sex = "女";
    }
    count = (count + 1) % 2;
    res.writeFlg = true;
    res.condition.signal();
} finally {
    res.lock.unlock();
}
// 读操作
try {
    res.lock.lock();
    try {
        if(!res.writeFlg) {
            res.condition.await();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(res.name + "," + res.sex);
    res.writeFlg = false;
    res.condition.signal();
} finally {
    res.lock.unlock();
}

wait和notfiy的区别

Wait和notify是Object类的方法,主要做
a.Wait、Notify一定要在synchronized里面进行使用。
b.Wait必须暂定当前正在执行的线程,并释放资源锁,让其他线程可以有机会运行
c. notify/notifyall: 唤醒因锁池中的线程,使之运行

注意:一定要在线程同步中使用,并且是同一个锁的资源

wait和sleep的区别

a、wait()方法是Object类的,sleep是Thread类的
b、sleep()方法的过程中,线程不会释放对象锁。它只是暂停程序执行,让出CPU给其他线程调度,但监控依然保持,时间到了自动恢复运行。
wait()执行的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有调用此对象的notfiy才会进入运行状态

synchronized和lock锁的区别

Lock锁是JDK1.5之后新增的
a、Lock接口可以尝试非阻塞地获取锁(在截止时间到了依旧无法获取锁,则返回),而synchronize是阻塞地获取锁。
b、Lock锁需要手动获取锁和释放锁,synchronize释放锁的时间是未知的
一个自动挡一个手动挡
c、Lock锁使用AQS原理实现,synchronize使用监视器实现。
d、synchronized是使用wait和notify实现,Lock锁里面的LockSupport是使用pack和unpack实现。

LockSupport的pack/unpack与Synchronized的wait/notify区别?

Wait/notify存在interrupt的时候会中断不在执行。
Pack/unpack存在interrupt的时候会先执行结束,然后再执行中断。


相关文章链接:
多线程基础
锁的深入化
锁的优化
Java内存模型(JMM)
Volatile解决JMM的可见性问题
Volatile的伪共享和重排序
CAS无锁模式及ABA问题
Synchronized锁
Lock锁
AQS同步器
Condition
CountDownLatch同步计数器
Semaphore信号量
CyclicBarrier屏障
线程池
并发队列
Callable与Future模式
Fork/Join框架
Threadlocal
Disruptor框架
如何优化多线程总结

相关文章

网友评论

    本文标题:并发编程-线程安全与解决方案

    本文链接:https://www.haomeiwen.com/subject/kvvviktx.html