• 同步代码块、同步方法解决数据安全问题、线程安全的类及Lock锁


    目录

    一、同步代码块解决数据安全问题

    二、同步方法解决数据安全问题

    三、线程安全的类

    四、Lock锁


    一、同步代码块解决数据安全问题

    安全问题出现的条件?

    是多线程环境

    有共享数据

    有多条语句操作共享数据

    如何解决多线程安全问题呢?

    基本思想:让程序没有安全问题的环境

    怎么实现呢?

    把多条语句操作共享数据的代码该给锁起来,让任意时刻只能有一个线程执行即可

    Java提供了同步代码块的方式解决

    同步代码块格式:

    1. synchronized(任意对象) {
    2. 多条语句操作共享数据的代码
    3. }

    synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看出是一把锁

    同步的好处和弊端:

    ● 好处:解决了多线程的数据安全问题

    ● 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

    代码演示:

    1. public class SellTicket implements Runnable {
    2. private int tickets = 100;
    3. private Object obj = new Object();
    4. @Override
    5. public void run() {
    6. while (true) {
    7. //tickets = 100;
    8. //t1,t2,t3
    9. //假设t1抢到了CPU的执行权
    10. //假设t2抢到了CPU的执行权
    11. synchronized (obj) {
    12. //t1进来后,就会把这段代码给锁起来
    13. if (tickets > 0) {
    14. try {
    15. Thread.sleep(100);
    16. //t1休息100毫秒
    17. } catch (InterruptedException e) {
    18. e.printStackTrace();
    19. }
    20. //窗口1正在出售第100张票
    21. System.out.println(Thread.currentThread().getName() + "正在出售
    22. 第" + tickets + "张票");
    23. tickets--; //tickets = 99;
    24. }
    25. }
    26. //t1出来了,这段代码的锁就被释放了
    27. }
    28. }
    29. }
    30. public class SellTicketDemo {
    31. public static void main(String[] args) {
    32. SellTicket st = new SellTicket();
    33. Thread t1 = new Thread(st, "窗口1");
    34. Thread t2 = new Thread(st, "窗口2");
    35. Thread t3 = new Thread(st, "窗口3");
    36. t1.start();
    37. t2.start();
    38. t3.start();
    39. }
    40. }

    二、同步方法解决数据安全问题

    同步方法的格式:

    同步方法:就是把synchronized关键字加到方法上

    1. 修饰符 synchonized 返回值类型 方法名(方法参数) {
    2. 方法体;
    3. }

    注意:同步锁的对象时this

    静态同步方法

    同步静态方法:就是把synchronized关键字加到静态方法上

    1. 修饰符 static synchonized 返回值类型 方法名(方法参数) {
    2. 方法体;
    3. }

    注意:同步静态方法的锁对象时类名.class

    代码演示:

    1. public class SellTicket implements Runnable {
    2. private static int tickets = 100;
    3. private int x = 0;
    4. @Override
    5. public void run() {
    6. while (true) {
    7. sellTicket();
    8. }
    9. }
    10. // 同步方法
    11. private synchronized void sellTicket() {
    12. if (tickets > 0) {
    13. try {
    14. Thread.sleep(100);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. System.out.println(Thread.currentThread().getName() + "正在出售第" +
    19. tickets + "张票");
    20. tickets--;
    21. }
    22. }
    23. // 静态同步方法
    24. private static synchronized void sellTicket() {
    25. if (tickets > 0) {
    26. try {
    27. Thread.sleep(100);
    28. } catch (InterruptedException e) {
    29. e.printStackTrace();
    30. }
    31. System.out.println(Thread.currentThread().getName() + "正在出售第" +
    32. tickets + "张票");
    33. tickets--;
    34. }
    35. }
    36. }
    37. public class SellTicketDemo {
    38. public static void main(String[] args) {
    39. SellTicket st = new SellTicket();
    40. Thread t1 = new Thread(st, "窗口1");
    41. Thread t2 = new Thread(st, "窗口2");
    42. Thread t3 = new Thread(st, "窗口3");
    43. t1.start();
    44. t2.start();
    45. t3.start();
    46. }
    47. }

    三、线程安全的类

    StringBuffffer

    ● 线程安全,可变的字符序列

    ● 从版本JDK 5开始,被StringBuilder 替代。 通常应该使用StringBuilder类,因为它支持所有相同的操作,但它更快,因为它不执行同步

    Vector

    ● 从Java 2平台v1.2开始,该类改进了List接口,使其成为Java Collections Framework的成员。 与新的集合实现不同, Vector被同步。 如果不需要线程安全的实现,建议使用ArrayList代替Vector

    Hashtable

    ● 该类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键或者值

    ● 从Java 2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为Java Collections Framework的成员。 与新的集合实现不同, Hashtable被同步。 如果不需要线程安全的实现,建议使用HashMap代替Hashtable

    四、Lock锁

    为了方便更加清晰表达如何加锁和释放锁,JDK5以后提供了一个锁对象Lock,由于是Lock是接口,所以实际使用它的实现类ReentrantLock类来实例化

    ReentrantLock构造方法:

    方法名说明
    ReetrantLock()创建一个ReetrantLock的实例

    加锁解锁方法:

    方法名说明
    void lock()获得锁
    void unlock()释放锁

    代码演示:

    1. public class SellTicket implements Runnable {
    2. private int tickets = 100;
    3. private Lock lock = new ReentrantLock();
    4. @Override
    5. public void run() {
    6. while (true) {
    7. try {
    8. lock.lock();
    9. if (tickets > 0) {
    10. try {
    11. Thread.sleep(100);
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. }
    15. System.out.println(Thread.currentThread().getName() + "正在出售
    16. 第" + tickets + "张票");
    17. tickets--;
    18. }
    19. } finally {
    20. lock.unlock();
    21. }
    22. }
    23. }
    24. }
    25. public class SellTicketDemo {
    26. public static void main(String[] args) {
    27. SellTicket st = new SellTicket();
    28. Thread t1 = new Thread(st, "窗口1");
    29. Thread t2 = new Thread(st, "窗口2");
    30. Thread t3 = new Thread(st, "窗口3");
    31. t1.start();
    32. t2.start();
    33. t3.start();
    34. }
    35. }
  • 相关阅读:
    Linux下一键安装Python3&更改镜像源&虚拟环境管理技巧
    Linux学习笔记--高级
    常用vim命令
    WPF/C#:如何实现拖拉元素
    vite 搭建双入口
    2022年月饼包装出新规啦!一起来看看今年的月饼包装有多好看吧!
    iframe 跨域之间共享localStorage,sessionStorage
    Python- 文件处理
    基于springboot的医护人员排班系统 全套代码 全套文档
    Springboot普通类获取运行时环境,获取运行时容器,获取Bean,等等获取运行时一切参数总结大全
  • 原文地址:https://blog.csdn.net/m0_61961937/article/details/126863622