在使用synchronized方法時,我總結(jié)了使用的情形:
第一種情形:
/**
* Created by zhangzheming on 2018/1/12.
*/
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();
}
}

從上面的運(yùn)行結(jié)果可以看出:在嵌套方法中使用synchronized,多線程情況下是線程安全的。
第二種情況:
/**
* Created by zhangzheming on 2018/1/12.
*/
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 (Exception 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 (Exception 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();
}
}

此種情形主要是說明兩點(diǎn):
(1)在出現(xiàn)父子類繼承關(guān)系的情況下,父類的成員變量也可以被子類繼承。
(2)在父類和子類都使用synchronized ,出現(xiàn)多線程情況下,是線程安全的。
synchronized 的使用出現(xiàn)異常情況下,如果遇到異常,我們也需要處理異常情況,請看下面的代碼:
/**
* Created by zhangzheming on 2018/1/12.
*/
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 == 0){
Integer.parseInt("a");
}
}catch (InterruptedException e){
e.printStackTrace();
// (3) contiune;
//(2)System.out.println("log info i = "+i);
//(1)throw new RuntimeException();
}
}
}
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();
}
}
這段代碼其實(shí)將輸出變量i的累加值,但是每逢遇到被10整除的數(shù)時,就會遇到異?,F(xiàn)象,這種情況下,我們有三種解決辦法:
(1)第一種辦法:throw new RuntimeException(); 將運(yùn)行異常拋出,這樣程序就會停止下來,不會影響到后面的任務(wù),比較適合任務(wù)之前有先后順序的關(guān)聯(lián)關(guān)系;
(2)第二種辦法:System.out.println("log info i = "+i);將錯誤信息打印出來或者打印到日志中出,事后進(jìn)行分析和修復(fù)。
(3)第三種辦法:contiune; 那就是最壞的情況,忽略錯誤,不處理異常情況
不要使用String字符串加鎖,這樣會導(dǎo)致死循環(huán)產(chǎn)生
請看下面的例子:
package Thread;
/**
* Created by zhangzheming on 2018/1/15.
*/
public class StringLock {
public void method(){
// 使用字符串當(dāng)做對象
synchronized ("字符串常量"){
try{
while (true){
System.out.println("當(dāng)前線程:"+Thread.currentThread().getName()+"開始");
Thread.sleep(1000);
System.out.println("當(dāng)前線程:"+Thread.currentThread().getName()+"結(jié)束");
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args){
final StringLock stringLock = new StringLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
});
t1.start();
t2.start();
}
}

按照我們預(yù)想的,啟動兩個線程會在執(zhí)行結(jié)果中產(chǎn)生兩個線程交替進(jìn)行,但是與實(shí)際結(jié)果不相同,這是為什么?
原因在于字符串屬于引用類型,不管什么樣的字符串都是一個類型對象,這樣就導(dǎo)致了只有一個線程存在,回頭想想其實(shí)要解決這個問題,就是滿足synchronized 鎖住的是對象就可以了,修改如下:
package Thread;
/**
* Created by zhangzheming on 2018/1/15.
*/
public class StringLock {
public void method(){
// 使用字符串當(dāng)做對象
synchronized (new String("字符串常量")){
try{
while (true){
System.out.println("當(dāng)前線程:"+Thread.currentThread().getName()+"開始");
Thread.sleep(1000);
System.out.println("當(dāng)前線程:"+Thread.currentThread().getName()+"結(jié)束");
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args){
final StringLock stringLock = new StringLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
});
t1.start();
t2.start();
}
}
