多线程同步synchronized使用

当使用多线程访问同一个资源的时候,非常容易出现线程安全的问题(例如,当多个线程同时对一个数据进行修改的时候,会导致某些线程对数据的修改丢失)。
线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
因此,需要采用同步机制来解决这种问题。而Java主要提供了三种实现同步机制的方法。
一、synchronized(同步代码块)
1、synchronized块既可以把任意的代码段声明为synchronized,也可以指定上锁的对象,有非常高的灵活性。其用法如下:

synchronized(syncObject){
    //访问synchObject的代码
 }

2、synchronized块的使用

public class MyRunnable implements Runnable{
    private static final String TAG = "wq892373445";
    @Override
    public void run() {
        runClass();
    }
     private void runClass() {
        //synchronized (MyRunnable.class) {
        synchronized (TAG ) {
            for(int i = 0;i < 10;i++){
                Log.d(TAG,Thread.currentThread().getName() +  "  run Class");
                sleep();
            }

        //}
    }
    private void sleep() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
 Thread t0 = new Thread(new MyRunnable());
 Thread t1 = new Thread(new MyRunnable());
 Thread t2 = new Thread(new MyRunnable());
 t0.setName("线程1");
 t1.setName("线程2");
 t2.setName("线程3");
 t0.start();
 t1.start();
 t2.start();

运行结果如下:

//没有加synchronized 同步的结果。
2020-04-05 18:15:19.898 4297-4458/com.example.opencvdemo D/wq892373445: 线程3  run Class
2020-04-05 18:15:19.899 4297-4456/com.example.opencvdemo D/wq892373445: 线程2  run Class
2020-04-05 18:15:19.899 4297-4455/com.example.opencvdemo D/wq892373445: 线程1  run Class
2020-04-05 18:15:20.899 4297-4458/com.example.opencvdemo D/wq892373445: 线程3  run Class
2020-04-05 18:15:20.899 4297-4456/com.example.opencvdemo D/wq892373445: 线程2  run Class
2020-04-05 18:15:20.900 4297-4455/com.example.opencvdemo D/wq892373445: 线程1  run Class
2020-04-05 18:15:21.900 4297-4458/com.example.opencvdemo D/wq892373445: 线程3  run Class
2020-04-05 18:15:21.900 4297-4456/com.example.opencvdemo D/wq892373445: 线程2  run Class
2020-04-05 18:15:21.900 4297-4455/com.example.opencvdemo D/wq892373445: 线程1  run Class
//加synchronized 同步的结果。
2020-04-05 18:12:26.032 3755-3871/? D/wq892373445: 线程1  run Class
2020-04-05 18:12:27.032 3755-3871/com.example.opencvdemo D/wq892373445: 线程1  run Class
2020-04-05 18:12:28.032 3755-3871/com.example.opencvdemo D/wq892373445: 线程1  run Class
2020-04-05 18:12:29.033 3755-3872/com.example.opencvdemo D/wq892373445: 线程2  run Class
2020-04-05 18:12:30.035 3755-3872/com.example.opencvdemo D/wq892373445: 线程2  run Class
2020-04-05 18:12:31.036 3755-3872/com.example.opencvdemo D/wq892373445: 线程2  run Class
2020-04-05 18:12:32.037 3755-3884/com.example.opencvdemo D/wq892373445: 线程3  run Class
2020-04-05 18:12:33.038 3755-3884/com.example.opencvdemo D/wq892373445: 线程3  run Class
2020-04-05 18:12:34.039 3755-3884/com.example.opencvdemo D/wq892373445: 线程3  run Class

备注:从日志中可以看出可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程进行执行。代码执行完成后释放锁,让后才能让其他线程进行执行。这样的话就可以解决线程不安全问题,当多个线程共享同一个资源,不会受到其他线程的干扰。
二、同步方法
1、一个方法使用 synchronized 关键字修饰后,当一个线程A使用这个方法时,其他线程想使用这个方法时就必须等待,直到线程A使用完该方法。
注意:
静态同步方法的锁是给该类的 类对象 加锁。
非静态同步方法其实就是给 this对象 进行加锁。
2、代码示例:

public class MyRunnable implements Runnable{
    private static final String TAG = "wq892373445";

    private int tickets = 10;
    @Override
    public void run() {

        while (true) {
            if (tickets > 0)
                sell();
            else
                return;
        }

    }

    public synchronized void sell() {
        if (tickets > 0) {
            Log.d(TAG,Thread.currentThread().getName() + "卖出第" + tickets + "张票");

            tickets--;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    }
MyRunnable t = new MyRunnable();
new Thread(t, "窗口1").start();
new Thread(t, "窗口2").start();
new Thread(t, "窗口3").start();

运行结果如下:

//没有加synchronized 
2020-04-05 19:15:37.247 20573-20618/? D/wq892373445: 窗口1卖出第10张票
2020-04-05 19:15:37.247 20573-20619/? D/wq892373445: 窗口2卖出第9张票
2020-04-05 19:15:37.247 20573-20620/? D/wq892373445: 窗口3卖出第8张票
2020-04-05 19:15:37.747 20573-20618/? D/wq892373445: 窗口1卖出第7张票
2020-04-05 19:15:37.747 20573-20619/? D/wq892373445: 窗口2卖出第7张票
2020-04-05 19:15:37.747 20573-20620/? D/wq892373445: 窗口3卖出第6张票
2020-04-05 19:15:38.247 20573-20618/com.example.opencvdemo D/wq892373445: 窗口1卖出第5张票
2020-04-05 19:15:38.247 20573-20620/com.example.opencvdemo D/wq892373445: 窗口3卖出第5张票
2020-04-05 19:15:38.247 20573-20619/com.example.opencvdemo D/wq892373445: 窗口2卖出第4张票
2020-04-05 19:15:38.748 20573-20620/com.example.opencvdemo D/wq892373445: 窗口3卖出第3张票
2020-04-05 19:15:38.748 20573-20619/com.example.opencvdemo D/wq892373445: 窗口2卖出第3张票
2020-04-05 19:15:38.748 20573-20618/com.example.opencvdemo D/wq892373445: 窗口1卖出第2张票
2020-04-05 19:15:39.248 20573-20620/com.example.opencvdemo D/wq892373445: 窗口3卖出第1张票
2020-04-05 19:15:39.248 20573-20618/com.example.opencvdemo D/wq892373445: 窗口1卖出第1张票
2020-04-05 19:15:39.248 20573-20619/com.example.opencvdemo D/wq892373445: 窗口2卖出第1张票
//加synchronized 
2020-04-05 19:20:18.648 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第10张票
2020-04-05 19:20:19.148 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第9张票
2020-04-05 19:20:19.649 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第8张票
2020-04-05 19:20:20.149 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第7张票
2020-04-05 19:20:20.649 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第6张票
2020-04-05 19:20:21.150 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第5张票
2020-04-05 19:20:21.651 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第4张票
2020-04-05 19:20:22.151 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第3张票
2020-04-05 19:20:22.652 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第2张票
2020-04-05 19:20:23.153 21231-21305/com.example.opencvdemo D/wq892373445: 窗口1卖出第1张票
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值