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();
}
}