Java线程同步机制下的手动加锁和自动加锁

该代码示例展示了Java中多线程环境下可能出现的数据不一致问题,即线程不同步导致的脏数据。通过在`update`方法上使用`synchronized`关键字或`ReentrantLock`实现手动加锁,可以确保线程安全,避免数据异常。同步后,更新visitor变量的操作在低于30时不再发生,保证了线程同步的效果。
摘要由CSDN通过智能技术生成

多线程问题

先来看一段代码

/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
  private int visitor = 100;

  private void update() {
    if (visitor >= 30) {
        System.out.println(String.format("- 时间戳:%d【线程%s】修改visitor值", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
    
        visitor -= 30;
        
    }
    // SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    // Date date = new Date(System.currentTimeMillis());
    
    
  }

  public void threadControll() throws InterruptedException{
    Thread t1 = new Thread(() -> {
       System.out.println("Thread 1");
       update();
       System.out.println(String.format("- 时间戳:%d【线程%s】当前游客数量: %d", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
    
     }, "t1");
      Thread t2 = new Thread(() -> {
       System.out.println("Thread 2");
       update();
       System.out.println(String.format("- 时间戳:%d【线程%s】当前游客数量: %d", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
    
     }, "t2");
     Thread t3 = new Thread(() -> {
       System.out.println("Thread 3");
       update();
       System.out.println(String.format("- 时间戳:%d【线程%s】当前游客数量: %d", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
    
     }, "t3");
      Thread t4 = new Thread(() -> {
       System.out.println("Thread 4");
       update();
       System.out.println(String.format("- 时间戳:%d【线程%s】当前游客数量: %d", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
    
     }, "t4");
     Thread t5 = new Thread(() -> {
       System.out.println("Thread 5");
       update();
       System.out.println(String.format("- 时间戳:%d【线程%s】当前游客数量: %d", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
    
     }, "t5");

     t1.start();
     t2.start();
     t3.start();
     t4.start();
     t5.start();
     t1.join();
     t2.join();
     t3.join();
     t4.join();
     t5.join();
  }


   public static void main(String []args) {
     try {
        new Main().threadControll();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      System.out.println("Hello world!");
   }
}

这段代码会出现线程不同步问题。
程序中定义了5个线程对visitor值进行更改,并且读取操作,可以看到:

在这里插入图片描述

从输出就可以看出,数据出现了-50-20这样的脏数据。

我们能想到的解决方案就是加锁,加锁分为自动加锁和手动加锁。

自动加锁

使用sychronized关键字进行加锁
非常简单,只需要在方法前加synchronized关键字

  private synchronized void update() {
    if (visitor >= 30) {
        System.out.println(String.format("- 时间戳:%d【线程%s】修改visitor值", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
        visitor -= 30;
    }

再来看一下输出:
在这里插入图片描述
可以看到,数量在低于30的情况下,不支持修改了

手动加锁

使用JUC并发包的ReentrantLock进行手动加锁
可以将程序改为

private Lock lock = new ReentrantLock();

  private void update() {
    lock.lock();
    if (visitor >= 30) {
        System.out.println(String.format("- 时间戳:%d【线程%s】修改visitor值", System.currentTimeMillis(), Thread.currentThread().getName(), visitor));
        visitor -= 30;
    }
    lock.unlock();
  }

可以看到输出结果也是正常的:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘先生的u写倒了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值