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关键字拥有锁重入的功能,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象锁的,否则就死锁了。
  • 当存在父子继承关系时,子类是可以通过“可重入锁”调用父类的同步方法的。
  • 出现异常,锁自动释放。
  • 同步不具有继承性。
原文地址:https://www.cnblogs.com/hunter-56213/p/11052921.html