多线程(一)--synchronized

1.2 线程安全
线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

激烈的锁竞争会导致cpu使用率飙升,表现为应用访问慢,或者系统宕机。
所以,多线程编程要注意锁竞争的发生。

1.3 多个对象多个锁
关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁,所以,示例代码中那个线程先执行synchronized关键字的方法,那个线程就持有该方法所属对象的锁(Lock),两个对象,线程获得的就是两个不同的锁。
如果在静态方法上使用synchronized关键字,表示锁定.class类,类级别的锁(独占.class类)。


1.4 脏读

1.5 synchronized的可重入性

案例一:

public class ReenterObj {
	public synchronized void method1() {
		System.out.println("method1");
		method2();
	}

	public synchronized void method2() {
		System.out.println("method2");
		method3();
	}

	public synchronized void method3() {
		System.out.println("method3");
	}

	public static void main(String[] args) {
		ReenterObj reenterObj = new ReenterObj();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				reenterObj.method1();
			}
		});
		t1.start();
	}
}

关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象锁的。

“可重入锁”的概念是:自己可以再次获取自己的内部所。比如有1条线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。

案例二:

public class Demo {

	static class Main{
		public int i=10;
		public synchronized void operationSup() {
			try {
				i--;
				System.out.println("Main print i = " + i);
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	static class Sub extends Main{
		public synchronized void operationSub() {
			try {
				while (i > 0) {
					i--;
					System.out.println("Sub print i = " + i);
					Thread.sleep(100);
					this.operationSup();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws InterruptedException {
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				Sub sub = new Sub();
				sub.operationSub();
			}
		});

		t1.start();
	}
}

说明,子类完全可以通过“可重入锁”调用父类的同步方法的。

1.6 synchronized遇到异常时的处理

方法一:打日志

public class SyncException {
	private int i = 0;
	public synchronized void operation() {
		while (true) {
			try {
				i++;
				Thread.sleep(200);
				System.out.println(Thread.currentThread().getName() + ", i = " + i);
				if (i == 10) {
					Integer.parseInt("a");
				}
			} catch (Exception e) {
				e.printStackTrace();
				System.out.println(" log info i = " + i);
			}
		}
	}

	public static void main(String[] args) {
		final SyncException se = new SyncException();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				se.operation();
			}
		},"t1");
		t1.start();
	}
}

方法二:直接中断,释放锁

public class SyncException {
	private int i = 0;
	public synchronized void operation() {
		while (true) {
			try {
				i++;
				Thread.sleep(200);
				System.out.println(Thread.currentThread().getName() + ", i = " + i);
				if (i == 10) {
					Integer.parseInt("a");
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
				System.out.println(" log info i = " + i);
			}
		}
	}

	public static void main(String[] args) {
		final SyncException se = new SyncException();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				se.operation();
			}
		},"t1");
		t1.start();
	}
}

猜你喜欢

转载自blog.csdn.net/csdn_kenneth/article/details/82759566