synchronized关键字
介绍synchronized关键字之前有必要阐述一下线程安全的概念。“非线程安全”会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”,也就是取到的数据其实是被更改过的,如果是方法内部的私有变量不存在“非线程安全”的问题;而“线程安全”就是获得的实例变量的值是经过同步处理的,不会出现脏读的现象。synchronized就是保证同步的。
package chapter2.synch.method; public class MyObject { synchronized public void methodA() { try { System.out.println("begin methodA threadName="+Thread.currentThread().getName()+"--beginTime:"+System.currentTimeMillis()); Thread.sleep(5000); System.out.println("end methodA threadName="+Thread.currentThread().getName()+"--endTime:"+System.currentTimeMillis()); } catch (Exception e) { e.printStackTrace(); } } synchronized public void methodB() { try { System.out.println("begin methodB threadName="+Thread.currentThread().getName()+"--beginTime:"+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("end methodB threadName="+Thread.currentThread().getName()+"--endTime:"+System.currentTimeMillis()); } catch (Exception e) { e.printStackTrace(); } } public void methodC() { try { System.out.println("begin methodC threadName="+Thread.currentThread().getName()+"--beginTime:"+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("end methodC threadName="+Thread.currentThread().getName()+"--endTime:"+System.currentTimeMillis()); } catch (Exception e) { e.printStackTrace(); } } public void methodD() { try { synchronized (this) { System.out.println("begin methodD threadName="+Thread.currentThread().getName()+"--beginTime:"+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("end methodD threadName="+Thread.currentThread().getName()+"--endTime:"+System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } public void methodE() { try { Object object = new Object(); synchronized (object) { System.out.println("begin methodE threadName="+Thread.currentThread().getName()+"--beginTime:"+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("end methodE threadName="+Thread.currentThread().getName()+"--endTime:"+System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } public void methodF(Object object) { try { synchronized (object) { System.out.println("begin methodF threadName="+Thread.currentThread().getName()+"--beginTime:"+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("end methodF threadName="+Thread.currentThread().getName()+"--endTime:"+System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } }
package chapter2.synch.method; public class ThreadA extends Thread{ private MyObject myObject; public MyObject getMyObject() { return myObject; } public void setMyObject(MyObject myObject) { this.myObject = myObject; } @Override public void run() { super.run(); myObject.methodA(); } } package chapter2.synch.method; public class ThreadB extends Thread{ private MyObject myObject; public MyObject getMyObject() { return myObject; } public void setMyObject(MyObject myObject) { this.myObject = myObject; } @Override public void run() { super.run(); myObject.methodB(); } } package chapter2.synch.method; public class Run { public static void main(String[] args) { MyObject myObject = new MyObject(); ThreadA threadA = new ThreadA(); threadA.setMyObject(myObject); threadA.setName("A"); ThreadB threadB = new ThreadB(); threadB.setMyObject(myObject); threadB.setName("B"); threadA.start(); threadB.start(); } }
运行结果:(同步执行)
begin methodA threadName=A--beginTime:1560936665128
end methodA threadName=A--endTime:1560936670128
begin methodB threadName=B--beginTime:1560936670128
end methodB threadName=B--endTime:1560936672128
如果ThreadB 修改成myObject.methodC();
运行结果:(异步执行)
begin methodC threadName=B--beginTime:1560936788821
begin methodA threadName=A--beginTime:1560936788821
end methodC threadName=B--endTime:1560936790821
end methodA threadName=A--endTime:1560936793821
如果ThreadB 修改成myObject.methodD();
运行结果:(同步执行)
begin methodD threadName=B--beginTime:1560936856169
end methodD threadName=B--endTime:1560936858169
begin methodA threadName=A--beginTime:1560936858169
end methodA threadName=A--endTime:1560936863169
如果ThreadB 修改成myObject.methodE();
运行结果:(异步执行)
begin methodE threadName=B--beginTime:1560936949062
begin methodA threadName=A--beginTime:1560936949062
end methodE threadName=B--endTime:1560936951062
end methodA threadName=A--endTime:1560936954062
代码做如下修改:
package chapter2.synch.method; public class ThreadA extends Thread{ private MyObject myObject; private Object object; public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public MyObject getMyObject() { return myObject; } public void setMyObject(MyObject myObject) { this.myObject = myObject; } @Override public void run() { super.run(); myObject.methodF(object); } }
package chapter2.synch.method;
public class Run {
public static void main(String[] args) {
MyObject myObject = new MyObject();
Object object = new Object();
ThreadA threadA = new ThreadA();
threadA.setObject(object);
threadA.setMyObject(myObject);
threadA.setName("A");
ThreadA threadB = new ThreadA();
threadB.setMyObject(myObject);
threadB.setObject(object);
threadB.setName("B");
threadA.start();
threadB.start();
}
}
运行结果:(同步执行)
begin methodF threadName=A--beginTime:1560937583035
end methodF threadName=A--endTime:1560937585035
begin methodF threadName=B--beginTime:1560937585035
end methodF threadName=B--endTime:1560937587035
结论:对象锁。
如果synchronized加到static方法上是给Class类上锁,Class锁可以对类的所有实例对象起作用。
特点:
- synchronized关键字拥有锁重入的功能,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象锁的,否则就死锁了。
- 当存在父子继承关系时,子类是可以通过“可重入锁”调用父类的同步方法的。
- 出现异常,锁自动释放。
- 同步不具有继承性。