文档章节

synchronized锁对象的坑

RippleChan
 RippleChan
发布于 09/20 18:23
字数 606
阅读 14
收藏 0

    今天本来写点其他东西,碰巧写了一下synchronized,没想到掉坑里面了,大佬别笑。

    起初代码大概是这样的:

package com.ripplechan.part_1_2_3;

import java.util.concurrent.CountDownLatch;

/**
 * @author RippleChan
 * @date 2018-09-20
 * @time 18:05
 */
public class DataTest {

    public static void main(String[] args) throws InterruptedException {
        int count = 10000;
        CountDownLatch countDownLatch = new CountDownLatch(count * 1);
        Cal cal = new Cal(countDownLatch);
        for (int i = 0; i < count; i++) {
            new Thread(cal).start();
        }
        countDownLatch.await();
        System.out.println(cal.getSum());
    }

}

class Cal extends Thread {

    private Long sum = 0L;
    CountDownLatch countDownLatch;

    public Cal(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        synchronized (sum) {
            try {
                this.sum = sum + 1;
            }  finally {
                countDownLatch.countDown();
            }
        }
    }

    public Long getSum() {
        return sum;
    }

}

    你觉得答案是多少?为什么会这样?如何避免这种情况?

    看下如下代码,相信你会明白为什么了。

public class DatSalfByObject {

    public static void main(String[] args) throws InterruptedException {
        Long a = 1L;
        int i = System.identityHashCode(a);
        System.out.println(i);
        a = a + 1L;
        int i1 = System.identityHashCode(a);
        System.out.println(i1);
    }

}

    这里做个解释吧,this.sum = sum + 1;后,sum还是以前的sum么?为什么会这样?关键词,不可变对象。通过System.identityHashCode也看出来了,变了。既然对象都变了,sychronized能锁住么?锁的是之前的对象,没有丝毫意义。

    通过某大佬的指点,我得出一下集中方案:

1.直接锁this(锁方法和锁this本质一样);
2.将需要修改的对象再次封装;

    方案1:

class MyCal5 extends Thread {

    private Long sum = 0L;
    CountDownLatch countDownLatch;

    public MyCal5(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            synchronized (this) {
                this.sum = sum + 1;
            }
        }finally {
            countDownLatch.countDown();
        }
    }

    public Long getSum() {
        return sum;
    }

}

    方案2:

@Data
class User {

    private Long id = 0L;

}

class UserThread extends Thread {

    private User user;
    private CountDownLatch countDownLatch;

    public UserThread(User user,CountDownLatch countDownLatch) {
        this.user = user;
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        try {
            synchronized (user) {
                Long id = user.getId();
                user.setId(id + 1);
            }
        }finally {
            countDownLatch.countDown();
        }
    }

}

    最终,因为锁this消耗太大,所以还是推荐锁对象,但如何避免对象被修改呢?是考验JavaSE基础的时候了,代码如下:

package com.ripplechan.part_1_2_3;

import lombok.Data;

import java.util.concurrent.CountDownLatch;

/**
 * @author RippleChan
 * @date 2018-09-20
 * @time 17:38
 */
public class DatSalfByObject {

    public static void main(String[] args) throws InterruptedException {
        int count = 10000;
        User user = new User();
        CountDownLatch countDownLatch = new CountDownLatch(count);
        UserThread userThread = new UserThread(user, countDownLatch);
        for (int c = 0; c < 10000; c++) {
            new Thread(userThread).start();
        }
        countDownLatch.await();
        System.out.println(user.getId());
    }

}


@Data
class User {

    private Long id = 0L;

}

class UserThread extends Thread {

    private final User user;
    private final CountDownLatch countDownLatch;

    public UserThread(User user,CountDownLatch countDownLatch) {
        this.user = user;
        this.countDownLatch = countDownLatch;
    }


    @Override
    public void run() {
        try {
            synchronized (user) {
                Long id = user.getId();
                user.setId(id + 1);
            }
        }finally {
            countDownLatch.countDown();
        }
    }

}

    对,finnal修饰,哈哈,这是一把防止出错的锁。

© 著作权归作者所有

共有 人打赏支持
RippleChan
粉丝 48
博文 92
码字总数 25919
作品 0
朝阳
程序员
java线程的同步代码块关键字synchronized

Java 慎用方法级别的synchronized关键字 为什么要这么说呢, 因为笔者被这个坑过(其实是自己坑自己)╮(╯_╰)╭ 先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用...

Jasonisoft
2016/05/30
0
0
Java多线程 - 各种线程锁

多个线程同时对同一个对象进行读写操作,很容易会出现一些难以预料的问题。所以很多时候我们需要给代码块加锁,同一时刻只允许一个线程对某个对象进行操作。多线程之所以会容易引发一些难以发现...

嘉伟咯
2017/09/01
0
0
Java多线程基础篇(03)-synchronized关键字

1.引言 基本上所有的并发模式再解决线程冲突的时候,都是采用序列化访问共享资源的方案。这意味着在给定时刻只允许一个任务访问共享资源。通常这是通过在代码前面添加一条锁语句来实现的,这...

kukudeku
2016/09/20
53
0
synchronized锁机制 之 代码块锁

synchronized同步代码块 用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个较长时间的任务,那么B线程必须等待比较长的时间。这种情况下可以尝试使用syn...

harries
06/27
0
0
Java并发编程基础-锁-synchonized

前言: synchonized是java中普遍意义的锁,一般都会称之为重量锁。自从JDK1.6开始对synchonized进行优化,synchonized在某些情况下也会转变为偏向锁、轻量锁、重量锁,可以认为synchonized关...

black-star
09/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Redis的API应用

全局命令 1,查看所有键:keys * set school dongnao set hello world 2,键总数 dbsize //2个键,如果存在大量键,线上禁止使用此指令 3,检查键是否存在:exists key //存在返回1,不存在返...

这很耳东先生
26分钟前
1
0
Java GC机制详解

垃圾收集 Garbage Collection 通常被称为“GC”,本文详细讲述Java垃圾回收机制。 导读: 1、什么是GC 2、GC常用算法 3、垃圾收集器 4、finalize()方法详解 5、总结--根据GC原理来优化代码 ...

编程SHA
29分钟前
1
0
CMD 乱码永久解决方案

创建cmd.reg,内容如下,双击运行导入注册表。 Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe]"CodePage"=dword:0000fde9"FontFamil......

yeahlife
31分钟前
1
0
亿级Web系统搭建:单机到分布式集群

当一个Web系统从日访问量10万逐步增长到1000万,甚至超过1亿的过程中,Web系统承受的压力会越来越大,在这个过程中,我们会遇到很多的问题。为了解决这些性能压力带来问题,我们需要在Web系统...

onedotdot
35分钟前
1
0
Linux 命令优先级 —— alias、function、内部命令(make)

Linux 命令优先级 —— alias、function、内部命令(make) make 新建Makefile文件,在里面输入如下内容; # Makefile内容all:@echo "Make Command echo : Hello " 保存,执行 which make ,...

雪落青山
36分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部