JAVA多线程之synchronized,对象锁,类锁

        JAVA内置锁:java内置锁的两种体现就是对象锁和类锁,java内置锁是一个互斥锁,同时只能被一个线程拿到,线程进入同步方法时自动获取内置锁,退出方法时,释放内置锁。当一个线程A拿到内置锁,其他线程只能等待A执行完毕释放锁,才能有机会获取内置锁进入同步方法。

        对象锁:对象锁是用于对象实例方法,或者一个对象实例上的,每个对象实例只有一把锁,且各个对象实例的锁互不干扰。

        类锁:类锁是用于类的静态方法或者一个类的class对象,类锁只有一把。

        synchronized:用来修饰方法或者代码块,保证同一时刻只有一个线程执行被修饰的方法或代码块。

        内置锁和synchronized的关系:被synchronized修饰的方法或者代码块,java会自动给这个方法或代码块加上内置锁,线程必须拿到这个锁才能访问被synchronized修饰的方法或代码块。


       下面从synchronized的使用实例来加深对象锁和类锁的映像。

       

        持有对象锁的synchronized实例:

package com.zw;


/**
 * 对象锁:
 *	        用于对象实例的方法,每一个JAVA的实例对象都有且只有一个内置锁,线程进入同步方法或同步代码块时自动获取锁。
 * 类锁:
 * 	       用于静态方法,每个Class类只有一个类锁
 * 
 * 对象锁和类锁可同时出现,互不干扰
 * @author Administrator
 *
 */
public class TestSynchronized {

	public static void main(String[] args) {
		final TestSynchronized testSynchronized = new TestSynchronized();
		Thread t = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				testSynchronized.test1();
			}
		});
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				testSynchronized.test2();
			}
		});
		
		t.start();
		t2.start();
	}
	
	public synchronized void test1() {
		int i = 5;
		while(i-- > 0)
		{
			try {
				Thread.sleep(1 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("t	" + i);
		}
	}
	public void test2() {
		
		synchronized (this) {
			int i = 5;
			while(i-- > 0)
			{
				try {
					Thread.sleep(1 * 1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("m	" + i);
			}
		}
	}
}

输出结果:

t    4
t    3
t    2
t    1
t    0
m    4
m    3
m    2
m    1
m    0

        上面的实例中同时启动两个线程,分别调用不同的被synchronized修饰的方法。从输出结果中可以看出两个线程的执行顺序是线程t先执行完毕后t2才开始执行,这是因为当前只创建了一个实例对象testSynchronized,每个实例对象只有一把锁,同步方法的执行前提是线程必须得拿到内置锁。t先拿到了对象实例的内置锁,t2只能等t执行结束才能开始调用被 synchronized修饰的方法。

扫描二维码关注公众号,回复: 1764240 查看本文章

        持有类锁的synchronized实例:

package com.zw;


/**
 * 对象锁:
 *	        用于对象实例的方法,每一个JAVA的实例对象都有且只有一个内置锁,线程进入同步方法或同步代码块时自动获取锁。
 * 类锁:
 * 	       用于静态方法,每个Class类只有一个类锁
 * 
 * 对象锁和类锁可同时出现,互不干扰
 * @author Administrator
 *
 */
public class TestSynchronized {

	public static void main(String[] args) {
		final TestSynchronized testSynchronized = new TestSynchronized();
		Thread t = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				TestSynchronized.test1();
			}
		});
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				testSynchronized.test2();
			}
		});
		
		t.start();
		t2.start();
	}
	
	public static synchronized void test1() {
		int i = 5;
		while(i-- > 0)
		{
			try {
				Thread.sleep(1 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("t	" + i);
		}
	}
	public void test2() {
		
		synchronized (TestSynchronized.class) {
			int i = 5;
			while(i-- > 0)
			{
				try {
					Thread.sleep(1 * 1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("m	" + i);
			}
		}
	}
}

输出结果:

t    4
t    3
t    2
t    1
t    0
m    4
m    3
m    2
m    1
m    0

        从输出结果可以看出启动两个线程,还是t先执行,t2后执行,这是因为类锁只有一把,t先拿到,t2只能等待t结束。


        同时持有类锁和对象锁的synchronized实例:

package com.zw;


/**
 * 对象锁:
 *	        用于对象实例的方法,每一个JAVA的实例对象都有且只有一个内置锁,线程进入同步方法或同步代码块时自动获取锁。
 * 类锁:
 * 	       用于静态方法,每个Class类只有一个类锁
 * 
 * 对象锁和类锁可同时出现,互不干扰
 * @author Administrator
 *
 */
public class TestSynchronized {

	public static void main(String[] args) {
		final TestSynchronized testSynchronized = new TestSynchronized();
		Thread t = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				TestSynchronized.test1();
			}
		});
		Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				testSynchronized.test2();
			}
		});
		
		t.start();
		t2.start();
	}
	
	public static synchronized void test1() {
		int i = 5;
		while(i-- > 0)
		{
			try {
				Thread.sleep(1 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("t	" + i);
		}
	}
	public void test2() {
		
		synchronized (this) {
			int i = 5;
			while(i-- > 0)
			{
				try {
					Thread.sleep(1 * 1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("m	" + i);
			}
		}
	}
}

输出结果:

t    4
m    4
t    3
m    3
t    2
m    2
t    1
m    1
t    0
m    0

        从输出结果可以看出两个线程交替执行,也就说明类锁和对象锁可同时出现,互不影响。


      synchronized修饰方法和修饰代码块的区别

      synchronized修饰方法,因为同一时刻只能有一个线程访问同步方法,其他线程必须排队等候,若是持有锁的线程没有退出方法,其他线程都无法访问同步方法,就会造成死锁。为了缓解这个问题(只是缓解,没有根本解决),修饰代码块的方式就出现了,这种方式可以避免锁住整个方法,只需锁住重要的部分就行。

猜你喜欢

转载自blog.csdn.net/yewucainiao/article/details/75769508