多线程 synchronized关键字

 在多线程情况下,当多个线程操作同一个资源的时候,会出现安全问题,例如脏读(一个线程咋读取变量的时候,值已经被另一个线程改变)。

synchronized关键字:可用来同步方法或者代码块。有关synchronized,总结一下几条。

  1 synchronized关键字锁的是对象,当多个对象会创建多个锁,而达不到同步的效果。

  2 只有操作公共资源的时候才需要上锁,非公共资源没必要上锁。

  3 synchronized关键字拥有可重入锁。

  4 异常出现的时候,会自动释放锁。

  5 同步不具备继承性。

  6 sleep()方法不会释放锁。

  7wait()方法会释放锁。

  8 synchronized可同步方法,也可以同步代码块。

下面对其中几条进行验证;

方法类:

public class MyMethod {

	
	synchronized public void methodA(String username) throws InterruptedException{
		System.out.println(username);
		if(username.equals("a")){
			
			System.out.println(Thread.currentThread().getName()+"  into methodA");
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getName()+"  out methodA");
		}
		else {
			System.out.println(Thread.currentThread().getName()+"  into methodB");
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName()+"  out methodB");
		}
		/*while(true){
			
		}*/
	}
	//synchronized 锁代码块
	public static void methodB(String lock) throws InterruptedException{
		synchronized (lock) {
			System.out.println(Thread.currentThread().getName()+"  into lock");
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName()+"  out lock");
			
		}
	}
}

  

主线程:synchronized同步代码块。synchronized(this)锁的是当前对象。

public class Run {

	public static void main(String[] args) throws InterruptedException {
		
		MyMethod m1=new MyMethod();
		MyMethod m2=new MyMethod();
		String lock="";
		Thread t1 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodB(lock);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t1");
		Thread t2 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodB(lock);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t2");
		t1.start();
		t2.start();

	}

}

  控制台:

t2  into lock
t2  out lock
t1  into lock
t1  out lock

  synchronized同步方法,修改主线程如下

public class Run {

	public static void main(String[] args) throws InterruptedException {
		
		MyMethod m1=new MyMethod();
		MyMethod m2=new MyMethod();
		String lock="";
		Thread t1 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodA("a");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t1");
		Thread t2 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodA("b");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t2");
		t1.start();
		t2.start();

	}

}

  控制台输出:

b
t2  into methodB
t2  out methodB
a
t1  into methodA
t1  out methodA

  可以发现达到同步的效果。

   再次修改主线程代码如下:

public class Run {

	public static void main(String[] args) throws InterruptedException {
		
		MyMethod m1=new MyMethod();
		MyMethod m2=new MyMethod();
		String lock="";
		Thread t1 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m1.methodA("a");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t1");
		Thread t2 =new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					m2.methodA("b");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		},"t2");
		t1.start();
		t2.start();

	}

}

  控制台如下

b
a
t1  into methodA
t2  into methodB
t2  out methodB
t1  out methodA

  并且多次执行main方法,发现控制台打印顺序不同。此处调用的是两个对象,所以jvm会创建两个锁,互不影响,所以在锁,只能锁一个对象中的方法。证明synchronized锁的是对象。此过程中,我还测试了静态方法,当把methodA()方法改为静态的时候

两个对象一样会有同步的效果。

可重入锁概念:自己可以再次获取自己的内部锁。如有一个线程获得了某个对象的锁,此时这个对象还没有释放,当其再次想获取这个对象的锁的时候,还是可以获取的,否则会造成死锁。

  

  每一个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。

原文地址:https://www.cnblogs.com/hrlizhi/p/9409285.html