• 五、线程同步 synchronized


    五、线程同步 synchronized

    并发:同一个对象被多个线程同时操作

    1、多线程并发问题

    模拟买票

    1、CODE

    package mii.thread.demo05多线程问题;
    /**
     * 多线程同时操作一个对象
     * 买火车票例子
     * 【问题:多个线程操作同一资源,线程不安全,数据紊乱】
     */
    public class TestRunnable implements Runnable {
    
        // 票数
        private int ticketNum = 10;
    
        public void run() {
            while(ticketNum > 0){
                System.out.println(Thread.currentThread().getName() + 
                                   "-->买到了第 " + ticketNum-- + " 张票!");
                // 模拟延时
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            TestRunnable tt = new TestRunnable();
    
            new Thread(tt, "小明").start();
            new Thread(tt, "小红").start();
            new Thread(tt, "小刚").start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    2、Result

    在这里插入图片描述


    2、队列和锁 synchronized

    ▼处理多线程问题:

    多个线程同时访问并修改同一个对象,这时就需要线程同步。线程同步就是一种等待机制,多个同时需要访问此对象的线程进入这个对象的 对象等待池 形成队列,等待前面线程访问完毕,下一个线程再访问。

    ▼锁机制:

    由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制 synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可。

    ▼存在以下问题:

    • 一个线程持有锁会导致其他所有需要此锁的线程挂起(性能损失)
    • 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题
    • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题

    ▼synchronized

    1. synchronized 方法
      1. synchronized void method(){...}
    2. synchronized 块(块内必须是引用)
      1. synchronized (obj){...}

    ▼synchronized 修饰的称为 同步监视器,修饰方法时同步监视器就是this,当前对象本身

    1、CODE

    1、synchronized 方法
    package mii.thread.demo13线程同步;
    public class UnsafeBuyTicket implements Runnable {
    
        private int ticketNum = 10; // 票数
    
        public void run() {
            while(true){
                try {
                    boolean buy = buy();
                    if(!buy){
                        break;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        // synchronized 同步方法
        private synchronized boolean buy() throws InterruptedException {
            // 模拟延时
            Thread.sleep(100);
            if(ticketNum > 0){
                System.out.println(Thread.currentThread().getName() +
                        "-->买到了第 " + ticketNum-- + " 张票!,还剩" + 
                                   ticketNum + "张票...");
                return true;
            }else{
                System.out.println(Thread.currentThread().getName() +
                        "手慢了,购票失败!");
                return false;
            }
        }
    
        public static void main(String[] args) {
            UnsafeBuyTicket tt = new UnsafeBuyTicket();
    
            new Thread(tt, "小明").start();
            new Thread(tt, "小红").start();
            new Thread(tt, "小刚").start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    2、synchronized 块
    package mii.thread.demo13线程同步;
    public class UnsafeBuyTicket implements Runnable {
    
        private Integer ticketNum = 10; // 票数
    
        public void run() {
            while(true){
                try {
                    // 模拟延时
                    Thread.sleep(100);
                    synchronized (ticketNum){
                        if(ticketNum > 0){
                            System.out.println(Thread.currentThread().getName() +
                                    "-->买到了第 " + ticketNum-- + " 张票!,还剩" + 
                                               ticketNum + "张票...");
                        }else{
                            System.out.println(Thread.currentThread().getName() +
                                    "手慢了,购票失败!");
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            UnsafeBuyTicket tt = new UnsafeBuyTicket();
    
            new Thread(tt, "小明").start();
            new Thread(tt, "小红").start();
            new Thread(tt, "小刚").start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2、Result

    在这里插入图片描述

  • 相关阅读:
    dotConnect for Oracle .net Crack
    day7_C++
    AI杀疯!2023上半年至今有趣的AI算法(内附视频)
    LeetCode每日一题:1822. 数组元素积的符号 (简单) 位运算
    Element UI 多选表格【翻页多选】简易版(不支持翻页多选数据反显)
    电脑数据丢失如何恢复呢?
    MySQL基础篇之多表查询(内连接、外连接、自连接、子查询、union)
    高效工具类软件使用
    1.0 Spring体系架构介绍(基于4.x)
    LeetCode算法心得——和可被 K 整除的子数组(前缀和+HashMap)
  • 原文地址:https://blog.csdn.net/qq_30769437/article/details/126439535