一、對象鎖和類鎖
1、線程安全:當多個線程訪問某一個類(對象或者方法),這個類始終能夠表現出正確的行爲,
那麼此類(對象或者方法)是線程安全的
synchronized:可以在任意對象或者方法上加鎖,而加鎖的這段代碼稱爲‘互斥區’或者臨界區
2.對象鎖和類鎖具體參考:對象鎖和類鎖示例
3.髒讀:讀到了共享變量中未刷新的值
二、重入鎖
1、重入鎖:關鍵字synchronized擁有鎖重入的功能,在使用synchronized的時候,當一個線程得到了一個對象的鎖
後,再次請求該對象時,是可以再次得到該對象的鎖,
2、重入鎖代碼示例:
/**
* synchronized的重入
*/
public class SyncDubbo1 {
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) {
final SyncDubbo1 sd = new SyncDubbo1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sd.method1();
}
});
t1.start();
}
}
/**
* synchronized的重入
*/
public class SyncDubbo2 {
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) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Sub sub = new Sub();
sub.operationSub();
}
});
t1.start();
}
}
三、代碼塊鎖
1、代碼塊鎖示例:可以使用任意的Object加鎖,用法比較靈活,不要使用String的常量加鎖,會出現死循環的問題
/**
* 使用synchronized代碼塊加鎖,比較靈活
*
*/
public class ObjectLock {
public void method1(){
synchronized (this) { //對象鎖
try {
System.out.println("do method1..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method2(){ //類鎖
synchronized (ObjectLock.class) {
try {
System.out.println("do method2..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Object lock = new Object();
public void method3(){ //任何對象鎖
synchronized (lock) {
try {
System.out.println("do method3..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final ObjectLock objLock = new ObjectLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method2();
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method3();
}
});
t1.start();
t2.start();
t3.start();
}
}
/**
* 同一對象屬性的修改不會影響鎖的情況
*
*/
public class ModifyLock {
private String name ;
private int age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public synchronized void changeAttributte(String name, int age) {
try {
System.out.println("當前線程 : " + Thread.currentThread().getName() + " 開始");
this.setName(name);
this.setAge(age);
System.out.println("當前線程 : " + Thread.currentThread().getName() + " 修改對象內容爲: "
+ this.getName() + ", " + this.getAge());
Thread.sleep(2000);
System.out.println("當前線程 : " + Thread.currentThread().getName() + " 結束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final ModifyLock modifyLock = new ModifyLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("張三", 20);
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("李四", 21);
}
},"t2");
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
2、對象鎖屬性修改示例:鎖對象的改變問題,當還是用一個對象進行加鎖的時候,要注意對象本身是發生改變的時候,那麼持有的鎖就不同。如果對象本身不發生改變,那麼依然是同步的,即使是對象的屬性發生了改變
/**
* 同一對象屬性的修改不會影響鎖的情況
*
*/
public class ModifyLock {
private String name ;
private int age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public synchronized void changeAttributte(String name, int age) {
try {
System.out.println("當前線程 : " + Thread.currentThread().getName() + " 開始");
this.setName(name);
this.setAge(age);
System.out.println("當前線程 : " + Thread.currentThread().getName() + " 修改對象內容爲: "
+ this.getName() + ", " + this.getAge());
Thread.sleep(2000);
System.out.println("當前線程 : " + Thread.currentThread().getName() + " 結束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final ModifyLock modifyLock = new ModifyLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("張三", 20);
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("李四", 21);
}
},"t2");
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
3、死鎖問題:死鎖問題,在設計程序時就應該避免雙方相互持有對方的鎖的情況
4.synchronized代碼塊對字符串的鎖,注意String常量池的緩存功能