java 多线程、锁的问题 synchronized
 package com.thread.main;

import org.junit.jupiter.api.Test;

/**
 * Created by Administrator on 2017/6/13.
 */
public class MyThread{
    @Test
    public void main() {
        new B().start();
        new C().start();
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}


class Home {
    private static Home home;
    private Home(){}
    public static Home getInstance(){
        if (home == null) {
            synchronized (Home.class) {
                home = new Home();
            }
        }
        return home;
    }
    public static String name;
    public synchronized String into(String name1) {
        System.out.println(name1+"进来了");
        this.name = name1;
        if ("张三".equals(name1)) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return name;
    }
}
class B extends Thread{
    @Override
    public void run() {
        Home home = Home.getInstance();
        System.out.println("B:"+home.into("张三"));
    }
}
class C extends Thread{
    @Override
    public void run() {
        Home home = Home.getInstance();
        System.out.println("C:"+home.into("李四"));
    }
}

打印结果:
张三进来了
李四进来了
C:李四
B:李四
synchronized不是方法同步吗,为什么针对多个线程同时访问的时候会出现这个问题呢,小弟这点没搞懂,请各位解答下,谢谢

3个回答

首先 如果你Home.getInstance(); 得到的如果是两个不一样的对象,那么这个现象就很好解释,因为是不同对象,那synchronized只是对相同对象两个线程调用才会起作用。
所以先执行张三 name=张三 然后sleep 再李四 name=李四 返回c:李四 然后sleep结束 name已经被修改为李四,然后就是b:李四。
其实在运行过程你也会发现,先是马上打印 张三 李四C:李四 这恰恰说明了 synchronized没有起作用

那为什么会得到两个不一样的对象呢?你发现你写的getInstance()的问题了没有?假设 B类和C类同时进入了 if,然后就会发生张三得到new Home();
李四再次得到new Home();
所以改成

     public static Home getInstance(){
        synchronized (Home.class) {
            if (home == null) {
                home = new Home();
            }
        }
        return home;
    }
Set2017
Set2017 受教了,谢谢您的回答
2 年多之前 回复

对象用volatile修饰

 private volatile static Home home;
Set2017
Set2017 加在哪呢,能详细点吗
2 年多之前 回复

分析了一下你的代码,原因应该是你的B和C的run方法,其中的两条语句不是同步的,比如你B线程执行了run方法,刚执行完还没执行打印语句就发生了阻塞,然后C线程去执行了代码,加之你的Home类中的name是静态变量,所以在C执行run之后就已经发生了变化,所以在B线程恢复执行的时候就变成了最新的name数值,有两点改进:
1、将run方法全部封装在Home的同步块中
2、将Home中的name设置为成员变量或者返回的时候返回一个新的string对象

Set2017
Set2017 谢谢您的回答
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!