synchronized同步方法的使用


1.方法内的变量为线程安全

public class HasSelfPrivateNum {

	public void addI(String userName){
		try{
			int num = 0;
			if(userName.equals("a")){
				num = 100;
				System.out.println("a set over!");
				Thread.sleep(2000);
			}else{
				num = 200;
				System.out.println("b set over!");
			}
			System.out.println(userName + " = " + num);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
	
}
public class ThreadA extends Thread{

	private HasSelfPrivateNum numRef;
	
	public ThreadA(HasSelfPrivateNum numRef){
//		super();
		this.numRef = numRef;
	}
	
	public void run(){
//		super.run();
		numRef.addI("a");
	}
	
}
public class ThreadB extends Thread{

	private HasSelfPrivateNum numRef;
	
	public ThreadB(HasSelfPrivateNum numRef){
		this.numRef = numRef;
	}
	
	public void run(){
		numRef.addI("b");
	}
	
}
public class MainFunction {

	public static void main(String[] args) {
		HasSelfPrivateNum numRef = new HasSelfPrivateNum();
		ThreadA threadA = new ThreadA(numRef);
		ThreadB threadB = new ThreadB(numRef);
		threadA.start();
		threadB.start();
	}

}

结果:

结论:方法中非变量不存在非线程安全问题,永远是线程安全的。这是方法内部的变量是私有的特性造成的。

=========================================

2.实例变量非线程安全

public class HasSelfPrivateNum {

	private int num = 0;
	
	public void addI(String userName){
		try{
			if(userName.equals("a")){
				num = 100;
				System.out.println("a set over!");
				Thread.sleep(2000);
			}else{
				num = 200;
				System.out.println("b set over!");
			}
			System.out.println(userName + " = " + num);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
	
}

仅修改以上代码,其余与1同。

结果:



将上述代码加上synchronized关键字:

public class HasSelfPrivateNum {

	private int num = 0;
	
	synchronized public void addI(String userName){
		try{
			if(userName.equals("a")){
				num = 100;
				System.out.println("a set over!");
				Thread.sleep(2000);
			}else{
				num = 200;
				System.out.println("b set over!");
			}
			System.out.println(userName + " = " + num);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
	
}

结果:可以看到的是,变成同步执行了(先执行哪个线程,就需要等这个线程执行完后才会执行下一个线程)


结论:在两个线程访问同一个对象中的同步方法时一定是线程安全的。

3.多个对象多个锁

代码在2的基础上,修改测试方法:

public class MainFunction {

	public static void main(String[] args) {
		HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
		HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
		ThreadA threadA = new ThreadA(numRef1);
		ThreadB threadB = new ThreadB(numRef2);
		threadA.start();
		threadB.start();
	}

}

测试结果:


结论:关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法当作锁,所以在上述示例中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,但前提是多个线程访问的是同一个对象!!

4.synchronized方法与锁对象

public class MyObject {
	synchronized public void methodA(){
		try{
			System.out.println("begin methodA threadName="+
					Thread.currentThread().getName());
			Thread.sleep(5000);
			System.out.println("end" +
					" time="+System.currentTimeMillis());
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
	
	public void methodB(){
		try{
			System.out.println("begin methodB threadName="+
					Thread.currentThread().getName() +
					"begin time="+System.currentTimeMillis());
			Thread.sleep(5000);
			System.out.println("end");
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}
public class ThreadA extends Thread{
	private MyObject myObject;
	
	public ThreadA(MyObject myObject){
		this.myObject = myObject;
	}
	
	public void run(){
		myObject.methodA();
	}
	
}
public class ThreadB extends Thread{
	private MyObject myObject;
	
	public ThreadB(MyObject myObject){
		this.myObject = myObject;
	}
	
	public void run(){
		myObject.methodB();
	}
	
}
public class Run {
	public static void main(String[] args) {
		MyObject myObject = new MyObject();
		ThreadA a = new ThreadA(myObject);
		a.setName("A");
		ThreadB b = new ThreadB(myObject);
		b.setName("B");
		a.start();
		b.start();
	}
}

运行结果:


将上述MyObject类中的methodB()方法中加入synchronized关键字后再测试结果如下


结论:

1)A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法;

2)A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需等待,也就是同步。


5.脏读

public class PublicVar {
	
	private String username="A";
	private String password="AA";
	
	synchronized public void setValue(String username,String password){
		try{
			this.username = username;
			Thread.sleep(5000);
			this.password=password;
			System.out.println("setValue method thread name="
					+ Thread.currentThread().getName()+
					" username="+username+" password="+password);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	 public void getValue(){
		System.out.println("getValue method thread name="
				+ Thread.currentThread().getName()+
				" username="+username+" password="+password);
	}
}
public class ThreadA extends Thread{

	private PublicVar publicVar;
	
	public ThreadA(PublicVar publicVar){
		this.publicVar = publicVar;
	}
	
	public void run(){
		publicVar.setValue("B", "BB");
	}
}
public class Test {

	public static void main(String[] args) {
		try{
			
			PublicVar publicVar = new PublicVar();
			ThreadA a = new ThreadA(publicVar);
			a.start();
			Thread.sleep(200);//打印结果受此值大小影响
			publicVar.getValue();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
}

结果:


将PublicVar类中的getValue()方法加上synchronized关键字后:


结论:要理解对象锁这个概念。简单来说就是当线程A获取了对象锁后,其他线程可以访问该对象的非synchronized方法。而如果该对象的所有方法都有synchronized修饰,则其他线程访问该对象时都要等A线程执行完后才可以访问。即对象锁的概念。

6.synchronized锁重入

可重入锁的概念是:自己可以再次获取自己的内部锁。(也支持在父子类继承环境中。)


7.出现异常,锁自动释放


8.同步不具有继承性

public class Main {

	synchronized public void serviceMethod(){
		try{
			System.out.println("int Main 下一步 sleep begin threadName=" +
					Thread.currentThread().getName() + 
					" time=" + System.currentTimeMillis());
			Thread.sleep(5000);
			System.out.println("int Main 下一步 sleep end threadName=" +
					Thread.currentThread().getName() + 
					" time=" + System.currentTimeMillis());
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
}
public class Sub extends Main{
	public void serviceMethod(){
		try{
			System.out.println("int Sub 下一步 sleep begin threadName " +
					Thread.currentThread().getName() + 
					" time=" + System.currentTimeMillis());
			Thread.sleep(5000);
			System.out.println("int Sub 下一步 sleep end threadName " +
					Thread.currentThread().getName() + 
					" time=" + System.currentTimeMillis());
			super.serviceMethod();
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
public class ThreadA extends Thread{

	private Sub sub;
	
	public ThreadA(Sub sub){
		this.sub = sub;
	}
	
	public void run(){
		sub.serviceMethod();
	}
	
}
public class ThreadB extends Thread{

	private Sub sub;
	
	public ThreadB(Sub sub){
		this.sub = sub;
	}
	
	public void run(){
		sub.serviceMethod();
	}
	
}
public class Test {

	public static void main(String[] args) {
		Sub sub = new Sub();
		ThreadA a = new ThreadA(sub);
		a.setName("a");
		a.start();
		
		ThreadB b = new ThreadB(sub);
		b.setName("b");
		b.start();
	}
	
}

结果:(非同步调用)


修改:在Sub类的方法上加上synchronized后再运行:(可以看到是同步调用)







猜你喜欢

转载自blog.csdn.net/satisfy_555/article/details/80921001
今日推荐