import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Created by csj on 2017/3/27. * 虽然在赋值的时候进行了同步,但在取值的时候有可能出现一些意想不到的意外,比如在读取实例变量时,该值已经被其他线程更改过了,这种情况就是脏读,根本原因是多个线程争夺实例变量引起的 * * * 总结:针对同一个对象锁 * 其中一个线程调用了PublicVar 对象的setValue()时,该线程就获得了这个对象的锁,其他也是使用这个对象锁的线程需要等待该线程执行完毕,但是可以调用其他的非同步的方法 * 当该线程调用了PublicVar 对象的setValue()时,其他线程如果要调用synchronized关键字的非setValue(),必须等该线程已经执行了一个完整的任务, * 针对两个对象锁或者多个对象锁如下 * 两个线程之间获得对象锁不一样不需要等待,就不需要等待另一个线程的执行完成才能执行。 */ public class PublicVar { Logger logger = LoggerFactory.getLogger(PublicVar.class); public String username = "a"; public String password = "aa"; //同步方法setValue() 的锁属于类PublicVar的实例 synchronized public void setValue(String username, String password) { try { this.username = username; Thread.sleep(5000); this.password = password; logger.info("setValue thread name = {}, username={}, password ={} ", Thread.currentThread().getName(), username, password); } catch (InterruptedException e) { e.printStackTrace(); } } /* * 第一种情况: * 如果这个方法没有添加synchronized,那么可以在任意时候进行调用, * main函数输出的结果如下 * 2017-03-27 21:36:57.276 [main] INFO PublicVar - thread name =main , username =b , password=aa * 2017-03-27 21:37:02.071 [Thread-0] INFO PublicVar - setValue thread name = Thread-0, username=b, password =bb * * 第二种情况 * 在这个函数中添加了synchronized,那么在main(),必须先执行完一个线程后,另一个线程才能访问,因为两个线程用的是同一个对象锁 * 2017-03-27 21:46:15.744 [Thread-0] INFO PublicVar - setValue thread name = Thread-0, username=b, password =bb * 2017-03-27 21:46:15.748 [main] INFO PublicVar - thread name =main , username =b , password=bb * * */ synchronized public void getValue(){ logger.info("thread name ={} , username ={} , password={}", Thread.currentThread().getName(), username, password); } }
/** * Created by csj on 2017/3/25. */ public class ThreadA extends Thread { private PublicVar publicVar; public ThreadA(PublicVar publicVar) { super(); this.publicVar = publicVar; } @Override public void run() { super.run(); publicVar.setValue("b","bb"); } }
/** * Created by csj on 2017/3/25. * 两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果是以异步的方式运行的,没有同步,各自有锁 * 原因:synchronized 取的是对象锁,而不是把一段代码或方法当作锁,,所以哪个线程运行对应的方法,就持有该方法所属对象的锁Lock * 那么多个线程访问的同一个对象的情况下,其他线程如果要使用这个对象锁就只能先等待。 * 如果多个线程访问多个对象,则jvm会创建多个锁。 */ public class Run { public static void main(String[] args) { try { PublicVar publicVar = new PublicVar(); PublicVar publicVar1 = new PublicVar(); ThreadA threadA = new ThreadA(publicVar); ThreadA threadB = new ThreadA(publicVar1); threadB.start(); threadA.start(); Thread.sleep(200); publicVar.getValue(); } catch (InterruptedException e) { e.printStackTrace(); } } }