java多线程之-----对象及变量的并发访问1(synchronized同步方法)

来源:互联网 发布:js获取字符串字节长度 编辑:程序博客网 时间:2024/05/16 12:35

方法内部的变量为线程安全的

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

实例变量非线程安全

如果多个线程共同访问一个对象中的实例变量,则有可能出现“非线程安全”的问题。用线程访问的对象中如果有多个实例变量,则运行的结果可能有可能出现交叉的情况。如果只有一个实例变量则有可能出现覆盖的情况,看下面的测试:创建新的项目,HasSelfPrivateNum.java的代码如下:
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) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

ThreadA如下:

public class ThreadA extends Thread{    private HasSelfPrivateNum selfPrivateNum;    public ThreadA(HasSelfPrivateNum selfPrivateNum) {        // TODO Auto-generated constructor stub        super();        this.selfPrivateNum = selfPrivateNum;    }    @Override    public void run() {        // TODO Auto-generated method stub        super.run();        selfPrivateNum.addI("a");    }}

ThreadB:

public class ThreadB extends Thread{    private HasSelfPrivateNum selfPrivateNum;    public ThreadB(HasSelfPrivateNum selfPrivateNum) {        // TODO Auto-generated constructor stub        super();        this.selfPrivateNum = selfPrivateNum;    }    @Override    public void run() {        // TODO Auto-generated method stub        super.run();        selfPrivateNum.addI("b");    }}

测试代码:

public class Test1 {    public static void main(String[] args) throws InterruptedException {        HasSelfPrivateNum hasSelfPrivateNum  = new HasSelfPrivateNum();        ThreadA a = new ThreadA(hasSelfPrivateNum);        a.start();        ThreadB b = new ThreadB(hasSelfPrivateNum);        b.start();    }}

运行结果:

这里写图片描述
由上面个的结果可得到:
如果两个线程同时操作业务对象的实例变量,则有可能会出现非线程安全的问题,我们只需要在前面加上synchrionized字即可。更改后的代码如下:

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) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

再次运行代码:
这里写图片描述

实验结论:在两个线程访问同一个对象的同步方法时一定是线程安全的。

多个对象多个锁

上面的HasSelfPrivateNum类中有同步方法addI,说明此方法应该被顺序调用。修改执行代码如下:
public class Test1 {    public static void main(String[] args) throws InterruptedException {        HasSelfPrivateNum hasSelfPrivateNum  = new HasSelfPrivateNum();        HasSelfPrivateNum hasSelfPrivateNum2  = new HasSelfPrivateNum();        ThreadA a = new ThreadA(hasSelfPrivateNum);        a.start();        ThreadB b = new ThreadB(hasSelfPrivateNum2);        b.start();    }}

运行结果;
这里写图片描述

上面的事例是两个线程分别访问同一个类的两个不同实例的相对名称的同步方法,效果确实以异步的方式运行的,本示例由于创建了两个业务对象,在系统中产生了两个锁。所以运行结果是异步的,打印的结果就是先打印b,再打印a。明明加了synchronized关键字,但打印的顺序却是不是同步的,是交叉的,为什么是这样的结果?关键字synchronized取得的锁都是对象锁,而不是一段代码或方法(函数)当做锁,所以上面实例,那个线程先执行带synchronized关键字的方法,那个线程就持有该方法所属有的锁Lock。其他线程只能呈现等待状态。前提是多个线程访问同一个对象。如果多个线程访问多个队形,JVM就会创建多个锁,上面的实例就是创建了两个HasSelfPrivateNum 类的对象,所以就会产生两个锁
阅读全文
1 0
原创粉丝点击