首页 > 技术文章 > synchronized同步方法

xiazhenbin 2020-10-14 22:10 原文

package JavaMultiThread;
/*
 * 实例变量的非线程安全
 */
public class t3 {
    public static void main(String[] args) {
        HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
        HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
        
        ThreadA thread1 = new ThreadA(numRef1);
        thread1.start();
        
        ThreadB thread2 = new ThreadB(numRef1);
        thread2.start();
        
    }

}

class HasSelfPrivateNum{
    private int num = 0;
    synchronized public void addI(String username) {
        try {
            if(username.equals("a")) {
                num = 100;
                System.out.println("a set over!");
                Thread.sleep(2000);
            }else {
                num = 200;
                System.out.println("b set over!");
            }
            System.out.println(username + " num = " + num);
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}



class ThreadA extends Thread{
    private HasSelfPrivateNum numRef;
    public ThreadA(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }
    @Override
    public void run() {
        super.run();
        numRef.addI("a");
    }
}

class ThreadB extends Thread{
    private HasSelfPrivateNum numRef;
    public ThreadB(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }
    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }
}
a set over!
a num = 100
b set over!
b num = 200

 如果多个线程共同访问1个对象中的实例变量,则可能出现”非线程安全“问题,可能会出现覆盖的情况。“非线程安全”问题存在于“实例变量”中,如果是方法内部的变量,永远都是线程安全的,这由于方法内的变量是私有的。

用synchronized给方法加锁以后,在两个线程访问同一个对象中的同步方法时一定是线程安全的。本实验先打印a,后打印b。

  • 非线程安全:当多个线程对同一个对象中的实例变量进行并发访问时,产生的后果就是”脏读“,也就是读取到的数据其实是被修改过的。
  • 线程安全:获得的实例变量的值是经过同步处理的,不会出现脏读的现象
package JavaMultiThread;
/*
 * 多个对象多个锁
 */
public class t3 {
    public static void main(String[] args) {
        HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
        HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
        
        ThreadA thread1 = new ThreadA(numRef1);
        thread1.start();
        
        ThreadB thread2 = new ThreadB(numRef2);
        thread2.start();
        
    }

}

class HasSelfPrivateNum{
    private int num = 0;
    synchronized public void addI(String username) {
        try {
            if(username.equals("a")) {
                num = 100;
                System.out.println("a set over!");
                Thread.sleep(2000);
            }else {
                num = 200;
                System.out.println("b set over!");
            }
            System.out.println(username + " num = " + num);
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}



class ThreadA extends Thread{
    private HasSelfPrivateNum numRef;
    public ThreadA(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }
    @Override
    public void run() {
        super.run();
        numRef.addI("a");
    }
}

class ThreadB extends Thread{
    private HasSelfPrivateNum numRef;
    public ThreadB(HasSelfPrivateNum numRef) {
        super();
        this.numRef = numRef;
    }
    @Override
    public void run() {
        super.run();
        numRef.addI("b");
    }
}
a set over!
b set over!
b num = 200
a num = 100

两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果是异步的方式执行的。

关键字synchronized取得的锁都是对象锁,当多个线程访问同一个对象时,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,其他线程就只能呈等待状态。

但是如果是多个线程访问多个对象,则JVM会创建多个锁。

 

package JavaMultiThread;
/*
 *synchronized锁住的是对象(不加锁)
 */
public class t1 {
    public static void main(String[] args) {
        MyObject object = new MyObject();
        ThreadH a = new ThreadH(object);
        a.setName("A");
        
        ThreadH b = new ThreadH(object);
        b.setName("B");
        
        a.start();
        b.start();
    }
}

class MyObject{
    public void methodA() {
        try {
            System.out.println("begin methodA threadName = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end!");
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    
    
    
}


class ThreadH extends Thread{    
    private MyObject object;
    public ThreadH( MyObject object) {    //用MyObject对象创建Threada进程
        super();
        this.object = object;
    }
    
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}
begin methodA threadName = A
begin methodA threadName = B
end!
end!
package JavaMultiThread;
/*
 *synchronized锁住的是对象
 */
public class t1 {
    public static void main(String[] args) {
        MyObject object = new MyObject();
        ThreadH a = new ThreadH(object);
        a.setName("A");
        
        ThreadH b = new ThreadH(object);
        b.setName("B");
        
        a.start();
        b.start();
    }
}

class MyObject{
    synchronized public void methodA() {
        try {
            System.out.println("begin methodA threadName = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end!");
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    
    
    
}


class ThreadH extends Thread{    
    private MyObject object;
    public ThreadH( MyObject object) {    //用MyObject对象创建Threada进程
        super();
        this.object = object;
    }
    
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}
begin methodA threadName = A
end!
begin methodA threadName = B
end!

只要共享资源的读写访问才需要同步化

 

package JavaMultiThread;

public class t1 {
    public static void main(String[] args) {
        MyObject object = new MyObject();
        ThreadH a = new ThreadH(object);
        a.setName("A");
        
        ThreadC b = new ThreadC(object);
        b.setName("B"); 
        
        a.start();
        b.start();
    }
}

class MyObject{
    synchronized public void methodA() {
        try {
            System.out.println("begin methodA threadName = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end endTime = " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    public void methodB() {
        try {
            System.out.println("begin methodB threadName = " + Thread.currentThread().getName()
                    + " begin time = " + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}


class ThreadH extends Thread{    
    private MyObject object;
    public ThreadH( MyObject object) {    //用MyObject对象创建Threada进程
        super();
        this.object = object;
    }
    
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}

class ThreadC extends Thread{    
    private MyObject object;
    public ThreadC( MyObject object) {    //用MyObject对象创建Threada进程
        super();
        this.object = object;
    }
    
    @Override
    public void run() {
        super.run();
        object.methodB();
    }
}
begin methodA threadName = A
begin methodB threadName = B begin time = 1602684531118
end endTime = 1602684535614
end

从这个实验可以得知,虽然线程A先持有了object对象的锁,但线程B完全可以异步调用非synchronizd类型的方法。

 

package JavaMultiThread;

public class t1 {
    public static void main(String[] args) throws InterruptedException {
        MyObject object = new MyObject();
        ThreadH a = new ThreadH(object);
        a.setName("A");
        
        ThreadC b = new ThreadC(object);
        b.setName("B"); 
        
        a.start();
        Thread.sleep(500);
        b.start();
    }
}

class MyObject{
    synchronized public void methodA() {
        try {
            System.out.println("begin methodA threadName = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("end endTime = " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    synchronized public void methodB() {
        try {
            System.out.println("begin methodB threadName = " + Thread.currentThread().getName()
                    + " begin time = " + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("end");
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}


class ThreadH extends Thread{    
    private MyObject object;
    public ThreadH( MyObject object) {    //用MyObject对象创建Threada进程
        super();
        this.object = object;
    }
    
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}

class ThreadC extends Thread{    
    private MyObject object;
    public ThreadC( MyObject object) {    //用MyObject对象创建Threada进程
        super();
        this.object = object;
    }
    
    @Override
    public void run() {
        super.run();
        object.methodB();
    }
}
begin methodA threadName = A
end endTime = 1602684573421
begin methodB threadName = B begin time = 1602684573421
end

 总结一下:

  • A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。
  • A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需要等待,也就是出现了同步

 

读脏数据

package JavaMultiThread;
/*
 * 读脏数据:dirtyRead:发生脏数据的情况是在读取实例变量时,此值已经被其他线程更改过
 */
public class t7 {
    public String username = "Xia Zhenbin";
    public String password = "123456";
    
    public static void main(String[] args) {
        try {
            t7 temp = new t7();
            ThreadM thread = new ThreadM(temp);
            thread.start();
            Thread.sleep(200);    //sleep时间设置得短一些,那么第一个线程未执行完,第二个线程getInfo就执行完了
            temp.getInfo();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    synchronized public void setInfo(String username, String password) {
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setInfo method thread name= " +
            Thread.currentThread().getName() + " username = " + 
                    username + " password = " + password);

        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    
    public void getInfo() {
        System.out.println("getInfo method thread name = " + 
        Thread.currentThread().getName() + " username = " + username + " password = " + password);
    }
}

class ThreadM extends Thread{
    t7 temp = new t7();
    public ThreadM(t7 temp) {
        super();
        this.temp = temp;
    }
    
    @Override
    public void run() {
        super.run();
        temp.setInfo("Lu Yanbing", "654321");
    }
}
getInfo method thread name = main username = Lu Yanbing password = 123456
setInfo method thread name= Thread-0 username = Lu Yanbing password = 654321

 

使用synchronized同步锁

package JavaMultiThread;
/*
 * 读脏数据:dirtyRead:发生脏数据的情况是在读取实例变量时,此值已经被其他线程更改过
 */
public class t7 {
    public String username = "Xia Zhenbin";
    public String password = "123456";
    
    public static void main(String[] args) {
        try {
            t7 temp = new t7();
            ThreadM thread = new ThreadM(temp);
            thread.start();
            Thread.sleep(200);    //sleep时间设置得短一些,那么第一个线程未执行完,第二个线程getInfo就执行完了
            temp.getInfo();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    synchronized public void setInfo(String username, String password) {
        try {
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setInfo method thread name= " +
            Thread.currentThread().getName() + " username = " + 
                    username + " password = " + password);

        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    
    synchronized public void getInfo() {
        System.out.println("getInfo method thread name = " + 
        Thread.currentThread().getName() + " username = " + username + " password = " + password);
    }
}

class ThreadM extends Thread{
    t7 temp = new t7();
    public ThreadM(t7 temp) {
        super();
        this.temp = temp;
    }
    
    @Override
    public void run() {
        super.run();
        temp.setInfo("Lu Yanbing", "654321");
    }
}
setInfo method thread name= Thread-0 username = Lu Yanbing password = 654321
getInfo method thread name = main username = Lu Yanbing password = 654321

  

 

package JavaMultiThread;
/*
 * 锁重入:当一个线程得到一个对象锁后,再次请求此对象时是可以再次得到该对象的锁的。
 */
public class t8 {
    public static void main(String[] args) {
        ThreadQ thread = new ThreadQ();
        thread.start();
    }
}

class Service {
    synchronized public void service1() {
        System.out.println("This is service1!");
        service2();
    }
    
    synchronized public void service2() {
        System.out.println("This is service2!");
        service3();
        
    }
    
    synchronized public void service3() {
        System.out.println("This is service3!");
    }
}

class ThreadQ extends Thread {    
    @Override
    public void run() {
        super.run();
        Service service = new Service();
        service.service1();
    }
}
This is service1!
This is service2!
This is service3!

关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。这也就证明在一个synchronized方法 / 块内部调用本类的其他方法 /块时,是永远可以得到锁的。试想,如果对象锁还没有释放,当再次想要获得这个对象的锁的时候还是可以获取的,如果锁不可以重入的话,就会造成死锁!!!

可重入锁也支持在父子类继承的环境中。

 

同步锁不具有继承性

package JavaMultiThread;
/*
 * 同步锁不具有继承性
 */
public class t8 {
    public static void main(String[] args) {
        Sub sub = new Sub();
        
        ThreadA1 thread = new ThreadA1(sub);
        thread.setName("a");
        thread.start();
        
        ThreadB1 thread1 = new ThreadB1(sub);
        thread1.setName("b");
        thread1.start();
    }
}

class Main {
    synchronized public void serviceMethod() {
        try {
            System.out.println("int main 下一步 sleep begin threadName = " + Thread.currentThread().getName() + " time = " +
                    System.currentTimeMillis());
            
            Thread.sleep(5000);
            
            System.out.println("int main 下一步 sleep end threadName = " + Thread.currentThread().getName() + " time = " +
                    System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Sub extends Main {    
    @Override
    public void serviceMethod() {  //《==============这里没加同步锁synchronized
        try {
            System.out.println("int sub 下一步 sleep begin threadName = " + Thread.currentThread().getName() + " time = " + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("int sub 下一步 sleep end threadName = " + Thread.currentThread().getName() + " time = " + System.currentTimeMillis());            
            
            super.serviceMethod();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }        
    }
}

class ThreadA1 extends Thread{
    private Sub sub;
    
    public ThreadA1(Sub sub) {
        super();
        this.sub = sub;
    }
    
    @Override
    public void run() {
        super.run();
        sub.serviceMethod();
    }
}

class ThreadB1 extends Thread{
    private Sub sub;
    
    public ThreadB1(Sub sub) {
        super();
        this.sub = sub;
    }
    
    @Override
    public void run() {
        super.run();
        sub.serviceMethod();
    }
}
int sub 下一步 sleep begin threadName = a time = 1602925179611
int sub 下一步 sleep begin threadName = b time = 1602925179611      《=============出现了不同步
int sub 下一步 sleep end threadName = b time = 1602925184619
int sub 下一步 sleep end threadName = a time = 1602925184619
int main 下一步 sleep begin threadName = b time = 1602925184619
int main 下一步 sleep end threadName = b time = 1602925189634
int main 下一步 sleep begin threadName = a time = 1602925189634
int main 下一步 sleep end threadName = a time = 1602925194647

 

将子类继承父类的方法加同步锁synchronized

package JavaMultiThread;
/*
 * 同步锁不具有继承性
 */
public class t8 {
    public static void main(String[] args) {
        Sub sub = new Sub();
        
        ThreadA1 thread = new ThreadA1(sub);
        thread.setName("a");
        thread.start();
        
        ThreadB1 thread1 = new ThreadB1(sub);
        thread1.setName("b");
        thread1.start();
    }
}

class Main {
    synchronized public void serviceMethod() {
        try {
            System.out.println("int main 下一步 sleep begin threadName = " + Thread.currentThread().getName() + " time = " +
                    System.currentTimeMillis());
            
            Thread.sleep(5000);
            
            System.out.println("int main 下一步 sleep end threadName = " + Thread.currentThread().getName() + " time = " +
                    System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Sub extends Main {    
    @Override
    synchronized public void serviceMethod() {  //<=================这里加了同步锁
        try {
            System.out.println("int sub 下一步 sleep begin threadName = " + Thread.currentThread().getName() + " time = " + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("int sub 下一步 sleep end threadName = " + Thread.currentThread().getName() + " time = " + System.currentTimeMillis());            
            
            super.serviceMethod();
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }        
    }
}

class ThreadA1 extends Thread{
    private Sub sub;
    
    public ThreadA1(Sub sub) {
        super();
        this.sub = sub;
    }
    
    @Override
    public void run() {
        super.run();
        sub.serviceMethod();
    }
}

class ThreadB1 extends Thread{
    private Sub sub;
    
    public ThreadB1(Sub sub) {
        super();
        this.sub = sub;
    }
    
    @Override
    public void run() {
        super.run();
        sub.serviceMethod();
    }
}
int sub 下一步 sleep begin threadName = a time = 1602925318835  
int sub 下一步 sleep end threadName = a time = 1602925323851
int main 下一步 sleep begin threadName = a time = 1602925323851
int main 下一步 sleep end threadName = a time = 1602925328852
int sub 下一步 sleep begin threadName = b time = 1602925328852  《=========进程a执行完以后,进程b才开始执行,是不是同步了
int sub 下一步 sleep end threadName = b time = 1602925333853
int main 下一步 sleep begin threadName = b time = 1602925333853
int main 下一步 sleep end threadName = b time = 1602925338867

  

synchronized同步代码块

package JavaMultiThread;

public class t9 {
    public static void main(String[] args) {
        Task task = new Task();
        
        ThreadA2 thread = new ThreadA2(task);
        thread.start();
        
        ThreadB2 thread1 = new ThreadB2(task);
        thread1.start();
    }
}

class Task {
    public void doLongTimeTask(){
        for(int i = 0; i < 100; i++) {
            System.out.println("Nosynchronized threadName = " + Thread.currentThread().getName() + " i = " + (i + 1));
        }
        
        System.out.println("");
        synchronized(this) {
            for(int i = 0; i < 100; i++) {
                System.out.println("Synchronized threadName = " + Thread.currentThread().getName() + " i = " + (i + 1));

            }
        }
    }    
}

class ThreadA2 extends Thread{
    private Task task;
    
    public ThreadA2(Task task) {
        // TODO 自动生成的构造函数存根
        super();
        this.task = task;
    }
    
    @Override
    public void run() {
        super.run();
        task.doLongTimeTask();
    }
}

class ThreadB2 extends Thread{
    private Task task;
    
    public ThreadB2(Task task) {
        // TODO 自动生成的构造函数存根
        super();
        this.task = task;
    }
    
    @Override
    public void run() {
        super.run();
        task.doLongTimeTask();
    }
}
Nosynchronized threadName = Thread-0 i = 1
Nosynchronized threadName = Thread-0 i = 2
Nosynchronized threadName = Thread-0 i = 3
Nosynchronized threadName = Thread-0 i = 4
Nosynchronized threadName = Thread-0 i = 5
Nosynchronized threadName = Thread-0 i = 6
Nosynchronized threadName = Thread-0 i = 7
Nosynchronized threadName = Thread-0 i = 8
Nosynchronized threadName = Thread-1 i = 1  《======这里出现了不同步
Nosynchronized threadName = Thread-0 i = 9
Nosynchronized threadName = Thread-1 i = 2
Nosynchronized threadName = Thread-0 i = 10
Nosynchronized threadName = Thread-1 i = 3
Nosynchronized threadName = Thread-0 i = 11
Nosynchronized threadName = Thread-1 i = 4
Nosynchronized threadName = Thread-0 i = 12
Nosynchronized threadName = Thread-1 i = 5
Nosynchronized threadName = Thread-0 i = 13
Nosynchronized threadName = Thread-1 i = 6
Nosynchronized threadName = Thread-0 i = 14
Nosynchronized threadName = Thread-1 i = 7
Nosynchronized threadName = Thread-0 i = 15
Nosynchronized threadName = Thread-1 i = 8
Nosynchronized threadName = Thread-0 i = 16
Nosynchronized threadName = Thread-1 i = 9
Nosynchronized threadName = Thread-0 i = 17
Nosynchronized threadName = Thread-1 i = 10
Nosynchronized threadName = Thread-0 i = 18
Nosynchronized threadName = Thread-1 i = 11
Nosynchronized threadName = Thread-0 i = 19
Nosynchronized threadName = Thread-1 i = 12
Nosynchronized threadName = Thread-0 i = 20
Nosynchronized threadName = Thread-1 i = 13

Nosynchronized threadName = Thread-1 i = 14
Synchronized threadName = Thread-0 i = 1
Nosynchronized threadName = Thread-1 i = 15
Synchronized threadName = Thread-0 i = 2
Nosynchronized threadName = Thread-1 i = 16
Synchronized threadName = Thread-0 i = 3
Nosynchronized threadName = Thread-1 i = 17
Synchronized threadName = Thread-0 i = 4
Nosynchronized threadName = Thread-1 i = 18
Synchronized threadName = Thread-0 i = 5
Nosynchronized threadName = Thread-1 i = 19
Synchronized threadName = Thread-0 i = 6
Synchronized threadName = Thread-0 i = 7
Synchronized threadName = Thread-0 i = 8
Synchronized threadName = Thread-0 i = 9
Synchronized threadName = Thread-0 i = 10
Synchronized threadName = Thread-0 i = 11
Nosynchronized threadName = Thread-1 i = 20

Synchronized threadName = Thread-0 i = 12
Synchronized threadName = Thread-0 i = 13
Synchronized threadName = Thread-0 i = 14
Synchronized threadName = Thread-0 i = 15
Synchronized threadName = Thread-0 i = 16
Synchronized threadName = Thread-0 i = 17
Synchronized threadName = Thread-0 i = 18
Synchronized threadName = Thread-0 i = 19
Synchronized threadName = Thread-0 i = 20
Synchronized threadName = Thread-1 i = 1  《========synchronized同步代码块,这里是同步的
Synchronized threadName = Thread-1 i = 2
Synchronized threadName = Thread-1 i = 3
Synchronized threadName = Thread-1 i = 4
Synchronized threadName = Thread-1 i = 5
Synchronized threadName = Thread-1 i = 6
Synchronized threadName = Thread-1 i = 7
Synchronized threadName = Thread-1 i = 8
Synchronized threadName = Thread-1 i = 9
Synchronized threadName = Thread-1 i = 10
Synchronized threadName = Thread-1 i = 11
Synchronized threadName = Thread-1 i = 12
Synchronized threadName = Thread-1 i = 13
Synchronized threadName = Thread-1 i = 14
Synchronized threadName = Thread-1 i = 15
Synchronized threadName = Thread-1 i = 16
Synchronized threadName = Thread-1 i = 17
Synchronized threadName = Thread-1 i = 18
Synchronized threadName = Thread-1 i = 19
Synchronized threadName = Thread-1 i = 20

 当一个线程访问object的一个synchronized同步代码块时,另一个线程可以访问该object对象中的非synchronized(this)同步代码块。

从上例,可以看出不在synchronized块中就是异步执行的,在synchronized块中就是同步执行的。

 

package JavaMultiThread;
/*
 * synchronized代码块,当某一个线程访问Object对象的其中一个synchronized(this)代码块,那么其他线程访问该对象的别的所有的synchronized(this)代码块时均被阻塞
 * 这个例子也间接说明 synchronized锁住的是对象
 */

public class t9 {
    public static void main(String[] args) {
        Task task = new Task();
        
        ThreadA2 thread = new ThreadA2(task);
        thread.start();
        
        ThreadB2 thread1 = new ThreadB2(task);
        thread1.start();
    }
}

class Task {
    synchronized public void doLongTimeTask(){
        synchronized(this) {
            for(int i = 0; i < 20; i++) {
                System.out.println("Synchronized Method threadName = " + Thread.currentThread().getName() + " i = " + (i + 1));

            }
        }
    }    
    
    public void doprintInfoTask() {
        System.out.println("begin!");
        System.out.println("Synchronized Method threadName = " + Thread.currentThread().getName());
        System.out.println("end!");
    }
}

class ThreadA2 extends Thread{
    private Task task;
    
    public ThreadA2(Task task) {
        // TODO 自动生成的构造函数存根
        super();
        this.task = task;
    }
    
    @Override
    public void run() {
        super.run();
        task.doLongTimeTask();
    }
}

class ThreadB2 extends Thread{
    private Task task;
    
    public ThreadB2(Task task) {
        // TODO 自动生成的构造函数存根
        super();
        this.task = task;
    }
    
    @Override
    public void run() {
        super.run();
        task.doprintInfoTask();
    }
}
Synchronized Method threadName = Thread-0 i = 1
Synchronized Method threadName = Thread-0 i = 2
Synchronized Method threadName = Thread-0 i = 3
Synchronized Method threadName = Thread-0 i = 4
Synchronized Method threadName = Thread-0 i = 5
Synchronized Method threadName = Thread-0 i = 6
Synchronized Method threadName = Thread-0 i = 7
Synchronized Method threadName = Thread-0 i = 8
Synchronized Method threadName = Thread-0 i = 9
Synchronized Method threadName = Thread-0 i = 10
Synchronized Method threadName = Thread-0 i = 11
Synchronized Method threadName = Thread-0 i = 12
Synchronized Method threadName = Thread-0 i = 13
Synchronized Method threadName = Thread-0 i = 14
begin!
Synchronized Method threadName = Thread-0 i = 15
Synchronized Method threadName = Thread-1
Synchronized Method threadName = Thread-0 i = 16
end!
Synchronized Method threadName = Thread-0 i = 17
Synchronized Method threadName = Thread-0 i = 18
Synchronized Method threadName = Thread-0 i = 19
Synchronized Method threadName = Thread-0 i = 20

 

更改后:

package JavaMultiThread;
/*
 * synchronized代码块,当某一个线程访问Object对象的其中一个synchronized(this)代码块,那么其他线程访问该对象的别的所有的synchronized(this)代码块时均被阻塞
 * 这个例子也间接说明 synchronized锁住的是对象
 */

public class t9 {
    public static void main(String[] args) {
        Task task = new Task();
        
        ThreadA2 thread = new ThreadA2(task);
        thread.start();
        
        ThreadB2 thread1 = new ThreadB2(task);
        thread1.start();
    }
}

class Task {
    synchronized public void doLongTimeTask(){
        synchronized(this) {
            for(int i = 0; i < 20; i++) {
                System.out.println("Synchronized Method threadName = " + Thread.currentThread().getName() + " i = " + (i + 1));

            }
        }
    }    
    
    synchronized public void doprintInfoTask() {
        System.out.println("begin!");
        System.out.println("Synchronized Method threadName = " + Thread.currentThread().getName());
        System.out.println("end!");
    }
}

class ThreadA2 extends Thread{
    private Task task;
    
    public ThreadA2(Task task) {
        // TODO 自动生成的构造函数存根
        super();
        this.task = task;
    }
    
    @Override
    public void run() {
        super.run();
        task.doLongTimeTask();
    }
}

class ThreadB2 extends Thread{
    private Task task;
    
    public ThreadB2(Task task) {
        // TODO 自动生成的构造函数存根
        super();
        this.task = task;
    }
    
    @Override
    public void run() {
        super.run();
        task.doprintInfoTask();
    }
}
Synchronized Method threadName = Thread-0 i = 1
Synchronized Method threadName = Thread-0 i = 2
Synchronized Method threadName = Thread-0 i = 3
Synchronized Method threadName = Thread-0 i = 4
Synchronized Method threadName = Thread-0 i = 5
Synchronized Method threadName = Thread-0 i = 6
Synchronized Method threadName = Thread-0 i = 7
Synchronized Method threadName = Thread-0 i = 8
Synchronized Method threadName = Thread-0 i = 9
Synchronized Method threadName = Thread-0 i = 10
Synchronized Method threadName = Thread-0 i = 11
Synchronized Method threadName = Thread-0 i = 12
Synchronized Method threadName = Thread-0 i = 13
Synchronized Method threadName = Thread-0 i = 14
Synchronized Method threadName = Thread-0 i = 15
Synchronized Method threadName = Thread-0 i = 16
Synchronized Method threadName = Thread-0 i = 17
Synchronized Method threadName = Thread-0 i = 18
Synchronized Method threadName = Thread-0 i = 19
Synchronized Method threadName = Thread-0 i = 20
begin!
Synchronized Method threadName = Thread-1
end!

 在使用同步synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object

中所有其他synchronized(this)同步代码块的访问将被阻塞,这也说明synchronized使用的是“对象监听器”

 

    synchronized(非this对象x)同步代码块中的代码
 
 

验证三个结论

package JavaMultiThread;


public class t13 {
    public static void main(String[] args) {
        MyService1 service = new MyService1();
        MyObject1 object = new MyObject1();
        
        Thread thread = new MyThreadA5(service, object);
        thread.setName("a");
        thread.start();
        
        Thread thread1 = new MyThreadB5(service, object);
        thread1.setName("b");
        thread1.start();
    }
}

class MyObject1    {
    
}

class MyService1 {
    public void testMethod1(MyObject1 object) {
        synchronized(object) {
            try {
                    System.out.println("testMethod1 ____getLock time = " + System.currentTimeMillis() + " run ThreadName = " + Thread.currentThread().getName());
                    Thread.sleep(2000);            
                    System.out.println("testMethod1 releaseLock time = " + System.currentTimeMillis() + " run ThreadName = " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }
    }
}

class MyThreadA5 extends Thread{
    private MyService1 service;
    private MyObject1 object;
    
    public MyThreadA5(MyService1 service, MyObject1 object) {
        // TODO 自动生成的构造函数存根
        super();
        this.object = object;
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.testMethod1(object);
    }
}

class MyThreadB5 extends Thread{
    private MyService1 service;
    private MyObject1 object;
    
    public MyThreadB5(MyService1 service, MyObject1 object) {
        // TODO 自动生成的构造函数存根
        super();
        this.object = object;
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.testMethod1(object);
    }
}
testMethod1 ____getLock time = 1603094973637 run ThreadName = a
testMethod1 releaseLock time = 1603094975639 run ThreadName = a
testMethod1 ____getLock time = 1603094975639 run ThreadName = b
testMethod1 releaseLock time = 1603094977644 run ThreadName = b

可以看出是两个线程是同步的,因为synchronized(非this x对象),锁住的是用一个对象object。

 

synchronized给class类上锁

package SynchronizedCass;


public class t1 {
    public static void main(String[] args) {
        ThreadA thread = new ThreadA();
        thread.setName("进程a");
        thread.start();
        
        ThreadB thread1 = new ThreadB();
        thread1.setName("进程b");
        thread1.start();
    }
}

class Service {
    synchronized public static void printA() {
        try {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + " 在 " + System.currentTimeMillis() + " 进入printA ");
            Thread.sleep(3000);
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + " 在 " + System.currentTimeMillis() + " 离开printA ");
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
    
    synchronized public static void printB() {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + "进入printB");
        
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + "离开printB");
    }
}

class ThreadA extends Thread{
    @Override
    public void run() {
        super.run();
        Service.printA();
    }
}

class ThreadB extends Thread{
    @Override
    public void run() {
        super.run();
        Service.printB();
    }
}
线程名称为:进程a 在 1603096693630 进入printA 
线程名称为:进程a 在 1603096696637 离开printA 
线程名称为:进程b 在 1603096696637 进入printB
线程名称为:进程b 在 1603096696637 离开printB

 

 类锁和对象锁是不同的

package SynchronizedCass;
/*
 * 简单理解,类锁和对象锁不是同一个,当一个线程持有类锁时,其他线程还是可以拿到对象锁
 */

public class t1 {
    public static void main(String[] args) {
        Service service = new Service();
        Service service1 = new Service();
        
        ThreadA thread = new ThreadA(service);
        thread.setName("进程a");
        thread.start();
        
        ThreadB thread1 = new ThreadB(service);
        thread1.setName("进程b");
        thread1.start();
        
        ThreadC thread2 = new ThreadC(service);
        thread2.setName("进程c");
        thread2.start();
    }
}

class Service {
    synchronized public static void printA() {
        try {
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + " 在 " + System.currentTimeMillis() + " 进入printA ");
            Thread.sleep(3000);
            System.out.println("线程名称为:" + Thread.currentThread().getName()
                    + " 在 " + System.currentTimeMillis() + " 离开printA ");
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }

    
    synchronized public static void printB() {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 进入printB");
        
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 离开printB");
    }
    
    synchronized public void printC() {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 进入printC");
        
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 离开printC");
    }
}

class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        Service.printA();
    }
}

class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        Service.printB();
    }
}

class ThreadC extends Thread{
    private Service service;
    public ThreadC(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.printC();
    }
}
线程名称为:进程a 在 1603098873662 进入printA 
线程名称为:进程c 在 1603098873662 进入printC
线程名称为:进程c 在 1603098873662 离开printC
线程名称为:进程a 在 1603098878675 离开printA 
线程名称为:进程b 在 1603098878675 进入printB
线程名称为:进程b 在 1603098878675 离开printB

 

类锁的另一种表示方法

同步synchronized(class)代码块的作用其实和synchronized static方法的作用是一样的

package SynchronizedCass;
/*
 * 简单理解,类锁和对象锁不是同一个,当一个线程持有类锁时,其他线程还是可以拿到对象锁
 */

public class t1 {
    public static void main(String[] args) {
        Service service = new Service();
        Service service1 = new Service();
        
        ThreadA thread = new ThreadA(service);
        thread.setName("进程a");
        thread.start();
        
        ThreadB thread1 = new ThreadB(service1);
        thread1.setName("进程b");
        thread1.start();
        
    }
}

class Service {
    public static void printA() {    
        synchronized(Service.class) {    //类锁的另一种写法而已
            try {
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + " 在 " + System.currentTimeMillis() + " 进入printA ");
                Thread.sleep(5000);
                System.out.println("线程名称为:" + Thread.currentThread().getName()
                        + " 在 " + System.currentTimeMillis() + " 离开printA ");
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }            
        }
    }
    
    
    synchronized public static void printB() {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 进入printB");
        
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 离开printB");
    }
    
    synchronized public void printC() {
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 进入printC");
        
        System.out.println("线程名称为:" + Thread.currentThread().getName()
                + " 在 " + System.currentTimeMillis() + " 离开printC");
    }
}

class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        Service.printA();
    }
}

class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        Service.printB();
    }
}

class ThreadC extends Thread{
    private Service service;
    public ThreadC(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        service.printC();
    }
}
线程名称为:进程a 在 1603098946244 进入printA 
线程名称为:进程a 在 1603098951246 离开printA 
线程名称为:进程b 在 1603098951246 进入printB
线程名称为:进程b 在 1603098951246 离开printB

 

 

在JVM中具有String常量池缓存的功能,因此String和synchronized(string)一起使用的时候,要注意常量池带来的一些例外。

注:JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化

    • 为字符串开辟一个字符串常量池,类似于缓存区。

    • 创建字符串常量时,首先坚持字符串常量池是否存在该字符串。

    • 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。

  • 举个例子
  • String str1 = “hello”;
    String str2 = “hello”;
    System.out.printl("str1 == str2" : str1 == str2 ) //返回的是true 
package SynchronizedCass;
/*
 * 简单理解,类锁和对象锁不是同一个,当一个线程持有类锁时,其他线程还是可以拿到对象锁
 */

public class t1 {
    public static void main(String[] args) {
        Service service = new Service();
        
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

class Service {
    public static void print(String stringParam) {    
        try {
            synchronized (stringParam) {
                while(true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);                        
                }
            }
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        Service.print("AA");
    }
}

class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        Service.print("AA");
    }
}

 

A
A
A
A
A
A
A
...

 

两个线程持有相同的锁,A线程没有释放锁前,B线程不能持有该锁。

锁对象换成object以后,两个线程就编程异步的了。

package SynchronizedCass;
/*
 * 简单理解,类锁和对象锁不是同一个,当一个线程持有类锁时,其他线程还是可以拿到对象锁
 */

public class t1 {
    public static void main(String[] args) {
        Service service = new Service();
        
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

class Service {
    public static void print(Object object) {    
        try {
            synchronized (object) {
                while(true) {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);                        
                }
            }
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    @Override
    public void run() {
        super.run();
        Service.print(new Object());
    }
}

class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service) {
        // TODO 自动生成的构造函数存根
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        Service.print(new Object());
    }
}
A
B
B
A
B
A
A
B
A
B
B
A
B
A
A
B
A
B
A
B...

  

2.2.16 锁对象的改变

在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁的对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是一步的。

package SynchronizedCass;

/*
 * synchronized锁住的是lock对象,但是lock对象变了
 */

public class t2 {
    public static void main(String[] args) {
        MyService service = new MyService();
        
        ThreadA1 a = new ThreadA1(service);
        a.setName("A");
        a.start();
        
        ThreadB1 b = new ThreadB1(service);
        b.setName("B");
        b.start();
    }
}

class MyService {
    private String lock = "123";
    public void testMethod() {    
        try {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " begin " + System.currentTimeMillis());
                lock = "345";
                Thread.sleep(2000);                
                System.out.println(Thread.currentThread().getName() + " end " + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

class ThreadA1 extends Thread{
    private MyService service;
    public ThreadA1(MyService service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.testMethod();
    }
}

class ThreadB1 extends Thread{
    private MyService service;
    public ThreadB1(MyService service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.testMethod();
    }
}
A begin 1603113655979
B begin 1603113655979
A end 1603113657983
B end 1603113657983

 

注意:只要对象不变,即使对象的属性被改变了,运行的结果还是同步的,下面这个例子刚好说明这个问题。

package SynchronizedCass;
/*
 * synchronized锁住的是lock对象,但是lock对象变了
 */

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        Userinfo userinfo = new Userinfo();
        
        ThreadA1 a = new ThreadA1(service, userinfo);
        a.setName("A");
        a.start();
        Thread.sleep(50);
        
        ThreadB1 b = new ThreadB1(service, userinfo);
        b.setName("B");
        b.start();
    }
}

class Userinfo    {
    public String name = "Xi dada";
    public Userinfo() {
        // TODO 自动生成的构造函数存根
    }
    
    public void setUsername(String name) {
        this.name = name;
    }
}

class MyService {
    public void serviceMethodA(Userinfo userinfo) {    
        synchronized(userinfo) {
            try {
                System.out.println(Thread.currentThread().getName());
                System.out.println("Username = " + userinfo.name);                
                userinfo.setUsername("Xiazhen");
                Thread.sleep(3000);                
                System.out.println("end Time = " + System.currentTimeMillis());
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }            
        }
    }
}

class ThreadA1 extends Thread{
    private MyService service;
    private Userinfo userinfo;
    
    public ThreadA1(MyService service, Userinfo userinfo) {
        super();
        this.service = service;
        this.userinfo = userinfo;
    }
    @Override
    public void run() {
        service.serviceMethodA(userinfo);
    }
}

class ThreadB1 extends Thread{
    private MyService service;
    private Userinfo userinfo;
    
    public ThreadB1(MyService service, Userinfo userinfo) {
        super();
        this.service = service;
        this.userinfo = userinfo;
    }
    @Override
    public void run() {
        service.serviceMethodA(userinfo);
    }
}

 

A
Username = Xi dada
end Time = 1603114559708
B
Username = Xiazhen
end Time = 1603114562716

  

package SynchronizedCass;
/**
 * 内置类与静态内置类
 * @author user
 *
 */
public class t3 {
    public static void main(String[] args) {
        final OutClass.Inner inner = new OutClass.Inner();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                inner.method1();
            }
        });
        thread.setName("A");
        
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                inner.method2();
            }
        });
        thread1.setName("B");
        thread.start();
        thread1.start();
    }
}

class OutClass    {
    static class Inner{
        public void method1() {
            synchronized ("其他的锁") {
                for(int i = 1; i <= 10; i++) {
                    System.out.println(Thread.currentThread().getName() + " i =" + i);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
            }
        }
        
        public synchronized void method2() {
            for(int i = 11; i <= 20; i++) {
                System.out.println(Thread.currentThread().getName() + " i =" + i);
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }
    }
}
A i =1
B i =11
A i =2
B i =12
A i =3
B i =13
A i =4
B i =14
A i =5
A i =6
B i =15
B i =16
A i =7
B i =17
A i =8
B i =18
A i =9
B i =19
B i =20
A i =10

  

package SynchronizedCass;
/**
 * 内置类与静态内置类
 * @author user
 *
 */
public class t3 {
    public static void main(String[] args) {
        final OutClass.InnerClass1 inner1 = new OutClass.InnerClass1();
        final OutClass.InnerClass2 inner2 = new OutClass.InnerClass2();

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                inner1.method1(inner2);
            }
        });
        thread.setName("A");
        
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                inner1.method2();
            }
        });
        thread1.setName("B");
        
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                inner2.method1();
            }
        },"C");
        

        thread.start();
        thread1.start();
        thread2.start();

    }
}

class OutClass    {
    static class InnerClass1{
        public void method1(InnerClass2 class2) {
            String threadName = Thread.currentThread().getName();
            synchronized (class2) {
                System.out.println(threadName + "进入InnerClass1中的method1");
                for(int i = 0; i <= 10; i++) {
                    System.out.println(Thread.currentThread().getName() + " i =" + i);
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
                System.out.println(threadName + "离开InnerClass1中的method1");
            }
        }
        
        public synchronized void method2() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "进入InnerClass1中的method2");
            for(int i = 11; i <= 20; i++) {
                System.out.println(" j =" + i);
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            } 
            System.out.println(threadName + "离开InnerClass1中的method2");
        }
    }
    
    static class InnerClass2 {
        public synchronized void method1() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "进入InnerClass2中的method1");
            for(int i = 0; i <= 10; i++) {
                System.out.println(" k =" + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }    
            }
            System.out.println(threadName + "离开InnerClass2中的method1");
        }
    }
}
A进入InnerClass1中的method1
B进入InnerClass1中的method2
 j =11
 j =12
 j =13
 j =14
 j =15
 j =16
 j =17
 j =18
 j =19
 j =20
A i =0
A i =1
A i =2
A i =3
A i =4
A i =5
A i =6
A i =7
A i =8
A i =9
A i =10
B离开InnerClass1中的method2
A离开InnerClass1中的method1
C进入InnerClass2中的method1
 k =0
 k =1
 k =2
 k =3
 k =4
 k =5
 k =6
 k =7
 k =8
 k =9
 k =10
C离开InnerClass2中的method1

 一定注意锁的对象是谁!!!

 

推荐阅读