Java多线程--synchronized同步方法

synchronized同步方法是为了解决“非线程安全”的问题,所谓“非线程安全”是指多个线程对同一个对象中的变量进行并发访问时发生,产生“脏读”的情况。

一、方法内的变量为线程安全

“非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,也就是“线程安全”的了。
demo:

HasSelfPrivateNum类:

public class HasSelfPrivateNum {
    public void addI(String username){
        try{
            int num=0;
            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){
            e.printStackTrace();
        }
    }
}

A线程类

public class ThreadA extends Thread {
    private HasSelfPrivateNum numRef;
    public ThreadA (HasSelfPrivateNum numRef){
        super();
        this.numRef=numRef;
    }

    @Override
    public void run(){
        super.run();
        numRef.addI("a");
    }
}

B线程类:

public class ThreadB extends Thread {
    private HasSelfPrivateNum numRef;
    public ThreadB (HasSelfPrivateNum numRef){
        super();
        this.numRef=numRef;
    }

    @Override
    public void run(){
        super.run();
        numRef.addI("b");
    }
}

Main方法:

public class Run {
    public static void main(String[] args){
        HasSelfPrivateNum numRef=new HasSelfPrivateNum();
        ThreadA athread=new ThreadA(numRef);
        athread.start();
        ThreadB bthread=new ThreadB(numRef);
        bthread.start();
    }
}

运行结果:

a set over!
b set over!
b num=200
a num=100

从结果可以看出这是线程安全的且永久安全,这是方法内部的变量私有的特性的原因(num变量是属于方法内部的)。

二、实例变量非线程安全

如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”的问题;

用线程访问的对象中如果有多个实例变量,则运行的结果有可能出现交叉的情况;

如果对象仅有1个实例变量,则有可能出现覆盖的情况。

修改HasSelfPrivateNum类,如下:

public class HasSelfPrivateNum {
    private int num=0;
    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){
            e.printStackTrace();
        }
    }
}

运行Main方法,结果如下:

a set over!
b set over!
b num=200
a num=200

本实例中两个线程同时操作业务对象中的实例变量,产生了覆盖的情况,出现了“线程不安全”的问题。

解决方法:

 在public void addI(String username)方法钱加关键字synchronized即可,如下:
public 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){
            e.printStackTrace();
        }
    }
}

运行main方法,结果如下:

a set over!
a num=100
b set over!
b num=200

当多个线程访问同一个对象中的同步方法时一定是线程安全的。

因为是同步访问,所以先打印a,然后打印出b。

猜你喜欢

转载自blog.csdn.net/wxr15732623310/article/details/80569747