本人在学习过程中在一些书籍上关于synchroinzed同步代码块的解释总是如下
synchronized(obj){ ……}在使用同步代码块时锁住了obj对象其他线程同时无法访问obj对象,
这很容易让人产生一种误解,demo如下
package com.kezhu.test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.kezhu.proxy.People;
public class TestSThread {
public static void main(String args[]){
People p = new People();
p.setEar("123");
People p1 = new People();
p1.setEar("456");
People p2 = new People();
p2.setEar("1a");
People p3 = new People();
p3.setEar("1b");
Set<People> s = new HashSet<People>();
s.add(p);
s.add(p1);
s.add(p2);
Thread thread0 = new Thread(){
public void run(){
System.out.println("线程0开始");
synchronized(s){
System.out.println("线程进入同步块,创建迭代器");
Iterator<People> iter = s.iterator();
while (iter.hasNext()){
People px = iter.next();
System.out.println("同步打印方法打印到 : " + px.getEar());
if("123".equals(px.getEar())){
System.out.println("线程碰到123的people暂停等待");
try {
sleep(2000l);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
};
Thread thread1 = new Thread(() ->{
System.out.println("线程1开始");
System.out.println("开始加入p3 : " + p3.getEar());
s.add(p3);
});
thread0.start();
thread1.start();
}
}
以上代码看完是否觉得在thread0执行进入synchronized块时,thread1一定无法执行对set进行add操作?
但事实并非如此多次运行后可以发现在thread1依然可以在thread0线程进入synchronized块后执行add操作导致迭代发生异常
以下是个人对使用synchronized块的看法,如有不对,希望大家积极指出谢谢
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(obj)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(obj)同步代码块即可以运行不被synchronized修饰的代码对上个线程同步监视器obj做任何修改处理。
对于第二点我再做一些补充,在我个人看来synchronized(obj){}中的obj只是个监视器
实际synchronized(obj){}锁住的是{}中的实际代码而obj只是一个监视器,在有一个线程开始同步块时对obj进行监视,然后其他线程再想来进入{}代码块时
会因为obj已经被监视导致无法获取锁进行等待,然而obj这个监视器是完全可以在内存中被其他普通方法进行修改发生变化的