synchronized同步方法

  • 1.提出问题-实例变量非线程安全
  • 1.1 何为非线程安全?
  • 1.2 举例
  • 1.2.1 有私有变量的类HasPrivateNum (供多线程们去调用)
  • 1.2.2 线程A
  • 1.2.3 线程B
  • 1.2.4 开启AB线程共同访问1个对象
  • 1.2.5 执行结果(多次执行有几率出现如下结果)
  • 2. 解决问题-给方法上加synchronized
  • 2.1 synchronized修饰范围
  • 2.2 修改后的HasPrivateNum类
  • 2.3 执行结果(多次执行一定是这样)
  • 3.思考问题-如果是多个对象的锁
  • 3.1 修改Run类
  • 3.2 运行结果
  • 4.思考问题-非synchronized方法会锁着吗
  • 4.1修改HasPrivateNum类
  • 4.2修改线程B调用非synchronized方法
  • 4.3 run方法
  • 4.4 运行结果


1.提出问题-实例变量非线程安全

如果多个线程同时访问1个对象的实例变量,则可能出现"非线程安全"问题。

1.1 何为非线程安全?

我的理解是多个线程对一个实例变量操作会出现值被更改,不同步的情况。

1.2 举例

1.2.1 有私有变量的类HasPrivateNum (供多线程们去调用)

public class HasPrivateNum {
    private int num = 0;
    public void addNum(String userName){
        try{
            if (userName.equalsIgnoreCase("wang.dong")){
                num = 1;
                System.out.println("wang dong set over");
                Thread.sleep(2000);
            }else {
                num = 2;
                System.out.println("other man set over");
            }
            
            System.out.println(userName + " num = " + num);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

这个类里面有一个私有变量 num,在addNum()函数里根据传的userName不同而赋值.

1.2.2 线程A

public class ThreadA  extends Thread{
    
    private HasPrivateNum num;

    public ThreadA(HasPrivateNum num){
        super();
        this.num = num;
    }
    
    @Override
    public void run(){
        super.run();
        num.addNum("wang.dong");
    }
}

1.2.3 线程B

public class ThreadB extends Thread{
    private HasPrivateNum num;

    public ThreadB(HasPrivateNum num){
        super();
        this.num = num;
    }

    @Override
    public void run(){
        super.run();
        num.addNum("other man");
    }
}

1.2.4 开启AB线程共同访问1个对象

public class Run {
    public static void main(String[] args) {
        HasPrivateNum numRef = new HasPrivateNum();

        //A
        ThreadA aThread = new ThreadA(numRef);
        aThread.start();

        //B
        ThreadB bThread = new ThreadB(numRef);
        bThread.start();
    }
}

1.2.5 执行结果(多次执行有几率出现如下结果)

java线程池多线程异步执行 java多线程synchronized_线程安全


A和B这2个线程同时访问一个没有同步的方法,并给里面变量赋值,可能出现"非线程安全"问题

2. 解决问题-给方法上加synchronized

2.1 synchronized修饰范围

修饰对象

作用范围

作用对象

代码块

synchronized(this){}内

调用这个代码块的对象

方法(接口方法/构造方法不行)

整个方法

调用这个方法的实例对象

静态方法

整个方法

这个类的所有类对象(共用一把锁)


synchronized后面{}

这个类的所有对象(共用一把锁)

2.2 修改后的HasPrivateNum类

public class HasPrivateNum {
    private int num = 0;
    
    // add synchroized
    public synchronized void addNum(String userName){
        try{
            if (userName.equalsIgnoreCase("wang.dong")){
                num = 1;
                System.out.println("wang dong set over");
                Thread.sleep(2000);
            }else {
                num = 2;
                System.out.println("other man set over");
            }
            System.out.println(userName + " num = " + num);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

2.3 执行结果(多次执行一定是这样)

java线程池多线程异步执行 java多线程synchronized_synchronized_02


如图说明线程B是等待线程A执行完毕后并释放了锁,才能获取锁

3.思考问题-如果是多个对象的锁

在上面1.2.4里只定义了一个HasPrivateNum的对象,如果有个HasPrivateNum对象,AB线程范围不同的对象,会是同步还是异步呢?

3.1 修改Run类

public class RunTwo {
    public static void main(String[] args) {
        HasPrivateNum numRef_1 = new HasPrivateNum();
        HasPrivateNum numRef_2 = new HasPrivateNum();
        
        //A
        ThreadA aThread = new ThreadA(numRef_1);
        aThread.start();

        //B
        ThreadB bThread = new ThreadB(numRef_2);
        bThread.start();
    }
}

A线程和B线程分别用不同的对象

3.2 运行结果

java线程池多线程异步执行 java多线程synchronized_线程安全_03


因为A线程睡了2秒,说是后打印的,这个2个线程是异步运行的,不相互影响

这个结果说明关键字synchronized的锁是对象锁,不是把一段代码或函数锁住

4.思考问题-非synchronized方法会锁着吗

一个对象有synchronized方法和非synchronized方法,如果线程A占用了synchronized方法,线程B是否可以访问这个对象的非synchronized方法?

4.1修改HasPrivateNum类

public class HasPrivateNum {
    private int num = 0;

    // add synchroized
    public synchronized void addNum(String userName){
        try{
            if (userName.equalsIgnoreCase("wang.dong")){
                num = 1;
                System.out.println("wang dong set over");
                Thread.sleep(2000);
            }else {
                num = 2;
                System.out.println("other man set over");
            }
            System.out.println(userName + " num = " + num);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    // not synchronized
    public void anotherMethod(){
        try{
            System.out.println(Thread.currentThread().getName() + " anotherMethod begin");

            Thread.sleep(2000);

            System.out.println(Thread.currentThread().getName() + " anotherMethod end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

4.2修改线程B调用非synchronized方法

public class ThreadB extends Thread{
    private HasPrivateNum num;

    public ThreadB(HasPrivateNum num){
        super();
        this.num = num;
    }

    @Override
    public void run(){
        super.run();
        //num.addNum("other man");
        num.anotherMethod();
    }
}

4.3 run方法

public class Run {
    public static void main(String[] args) {
        HasPrivateNum numRef = new HasPrivateNum();

        //A
        ThreadA aThread = new ThreadA(numRef);
        aThread.start();

        //B
        ThreadB bThread = new ThreadB(numRef);
        bThread.start();
    }
}

4.4 运行结果

java线程池多线程异步执行 java多线程synchronized_线程安全_04


从结果看出线程A和线程B是异步执行的

  • 多个线程同时访问同一个object的synchronized(this)代码块时,一个时间只有一个线程,其他线程只能等待
  • 其他线程可以访问该object的非synchronized(this)代码块

这次暂时写这么多吧,加油!