• 【多线程 - 08、线程同步 synchronized】


    什么情况下会产生线程安全问题

    同时满足以下两个条件时:

    • 多个线程在操作共享的数据。
    • 操作共享数据的线程代码有多条。

    当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。

    例子:四个线程卖100张票

    public class ThreadTest {
        public static void main(String[] args) {
            synchronizeThread st = new synchronizeThread();
            new Thread(st,"1").start();
            new Thread(st,"2").start();
            new Thread(st,"3").start();
            new Thread(st,"4").start();
        }
    }
    class synchronizeThread implements Runnable {
        private int ticketNumber = 100;
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (ticketNumber > 0) {
                    System.out.println("线程【" + Thread.currentThread().getName() + "】卖出了一张票,现在剩余了【" + ticketNumber + "】张票");
                    ticketNumber--;
                } else {
                    break;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    运行结果:发现会有多个线程卖同一张票的情况发生,这就是线程安全问题。

    解决这样的问题就是线程同步的方式来实现。

    线程同步

    同步就是协同步调,按预定的先后次序进行运行。这里的同步千万不要理解成那个同时进行,应是指协同、协助、互相配合。线程同步是指多线程通过特定的设置来控制线程之间`的执行顺序(即所谓的同步)也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步,那线程之间是各自运行各自的

    synchronized 同步代码块

    即用synchronized关键字修饰的语句块。

    被该关键字修饰的语句块会自动被加上内置锁,被保护的语句代码所在的线程要执行,需要获得内置锁,否则就处于阻塞状态。

    代码

    synchronized(object){ 
    }
    
    • 1
    • 2

    括号里的这个对象可以是任意对象,这个对象一般称为同步锁。

    同步的前提

    同步中必须有多个线程并使用同一个锁。

    同步的好处

    解决了线程的安全问题。

    注意

    同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

    例子:四个线程卖100张票

    package cn.hyl.test1;
    
    public class ThreadTest {
        public static void main(String[] args) {
            synchronizeThread st = new synchronizeThread();
            new Thread(st,"1").start();
            new Thread(st,"2").start();
            new Thread(st,"3").start();
            new Thread(st,"4").start();
        }
    }
    class synchronizeThread implements Runnable {
        private Integer ticketNumber = 100;
        private Object object = new Object();
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
               synchronized (ticketNumber){
                   if (ticketNumber > 0) {
                       System.out.println("线程【" + Thread.currentThread().getName() + "】卖出了一张票,现在剩余了【" + ticketNumber + "】张票");
                       ticketNumber--;
                   } else {
                       break;
                   }
               }
            }
        }
    }
    
    • 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

    synchronized同步方法

    即用synchronized关键字修饰的方法。

    由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

    代码

    public synchronized void save(){}
    
    • 1

    注意

    • 对于普通同步方法,锁是当前实例对象。
    • 对于静态同步方法,锁是当前类的Class对象。
    • 对于同步方法块,锁是Synchonized括号里配置的对象。
  • 相关阅读:
    JZ70 矩形覆盖
    vue2知识点————(声明周期,vue动态组件 )
    android 设备如何对多个屏幕截图
    Uniapp离线打包SDK-模块配置
    Go函数并发情况的错误处理
    【Vue】集成百度地图
    面试常见问题丨深入解析Spring中Bean的整个初始化过程
    深度优先搜索遍历与广度优先搜索遍历
    对象混入的实现方式
    JavaIO系列——BufferedReader,BufferedWriter,PrintWriter,转换流
  • 原文地址:https://blog.csdn.net/qq_46023503/article/details/134340414