将任意对象作为对象监视器
synchronized同步代码块还支持任意对象,使用格式为synchronized(非this对象)
package Second; public class Service { private String usernameParam; private String passwordParam; private String anyString = new String(); public void setUsernamePassword(String username, String password) { try { synchronized (anyString) { System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); usernameParam = username; Thread.sleep(3000); passwordParam = password; System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Second; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.setUsernamePassword("a", "aa"); } }
package Second; public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.setUsernamePassword("b", "bb"); } }
package Second; public class Run { public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } }
package Second; public class Service { private String usernameParam; private String passwordParam; public void setUsernamePassword(String username, String password) { try { String anyString = new String(); synchronized (anyString) { System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入同步块"); usernameParam = username; Thread.sleep(3000); passwordParam = password; System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开同步块"); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package Second; public class Service { private String anyString = new String(); public void a() { try { synchronized (anyString) { System.out.println("a begin"); Thread.sleep(3000); System.out.println("a end"); } } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void b() { System.out.println("b begin"); System.out.println("b end"); } }
package Second; public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { super(); this.service = service; } @Override public void run() { service.a(); } }
package Second; public class ThreadB extends Thread { private Service service; public ThreadB(Service service) { super(); this.service = service; } @Override public void run() { service.b(); } }
package Second; public class Run { public static void main(String[] args) { Service service = new Service(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); } }
由于对象监视器不同,所以运行结果就是异步的
下面验证多个线程调用同一个方法是随机的
package Second; import java.util.ArrayList; import java.util.List; public class MyList { private List list = new ArrayList(); synchronized public void add(String username) { System.out.println("ThreadName=" + Thread.currentThread().getName() + "执行了add方法!"); list.add(username); System.out.println("ThreadName=" + Thread.currentThread().getName() + "退出了add方法!"); } synchronized public int getSize() { System.out.println("ThreadName=" + Thread.currentThread().getName() + "执行了getSize方法!"); int sizeValue = list.size(); System.out.println("ThreadName=" + Thread.currentThread().getName() + "退出了getSize方法!"); return sizeValue; } }
package Second; public class MyThreadA extends Thread { private MyList list; public MyThreadA(MyList list) { super(); this.list = list; } @Override public void run() { for (int i = 0; i < 100000; i++) { list.add("threadA" + (i + 1)); } } }
package Second; public class MyThreadB extends Thread { private MyList list; public MyThreadB(MyList list) { super(); this.list = list; } @Override public void run() { for (int i = 0; i < 100000; i++) { list.add("threadB" + (i + 1)); } } }
package Second; public class Test { public static void main(String[] args) { MyList mylist = new MyList(); MyThreadA a = new MyThreadA(mylist); a.setName("A"); a.start(); MyThreadB b = new MyThreadB(mylist); b.setName("B"); b.start(); } }
下面展示多线程出现脏读的情况
package Second; import java.util.ArrayList; import java.util.List; public class MyOneList { private List list = new ArrayList(); synchronized public void add(String data) { list.add(data); }; synchronized public int getSize() { return list.size(); }; }
package Second; public class MyService { public MyOneList addServiceMethod(MyOneList list, String data) { try { synchronized (list) { if (list.getSize() < 1) { Thread.sleep(2000); list.add(data); } } } catch (InterruptedException e) { e.printStackTrace(); } return list; } }
package Second; public class MyThread1 extends Thread { private MyOneList list; public MyThread1(MyOneList list) { super(); this.list = list; } @Override public void run() { MyService msRef = new MyService(); msRef.addServiceMethod(list, "A"); } }
package Second; public class MyThread2 extends Thread { private MyOneList list; public MyThread2(MyOneList list) { super(); this.list = list; } @Override public void run() { MyService msRef = new MyService(); msRef.addServiceMethod(list, "B"); } }
package Second; public class Run { public static void main(String[] args) throws InterruptedException { MyOneList list = new MyOneList(); MyThread1 thread1 = new MyThread1(list); thread1.setName("A"); thread1.start(); MyThread2 thread2 = new MyThread2(list); thread2.setName("B"); thread2.start(); Thread.sleep(6000); System.out.println("listSize=" + list.getSize()); } }
"脏读"出现了。出现的原因是两个线程以异步的方式返回list参数的size()大小。解决办法是“”同步化
package Second; public class MyService { public MyOneList addServiceMethod(MyOneList list, String data) { try { synchronized (list) { if (list.getSize() < 1) { Thread.sleep(2000); list.add(data); } } } catch (InterruptedException e) { e.printStackTrace(); } return list; } }
由于list参数对象在项目中是一份实例,是单例的,而且也正需要对list参数的getsize()方法做同步的调用,所以就对list参数进行同步处理