对象和变量的并发访问

文章介绍Java多线程中的同步,主要
1:synchronized 的使用。
2:非线程安全如何出现。
3:volatile的总用。

synchronized同步方法。

方法内的变量是线程安全的,
多个线程共同访问一个对象中的实例变量,可能出现非线程安全。
public class Tian{
    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(InterruptException e){
            e.printStackTrace();
        }
    }
}

//threadA
 public class ThreadA extends Thread {
    private Tian tian;
    public ThreadA(Tian tian) {
        super();
        this.tian = tian;
    }
    @Override
    public void run() {
        super.run();
        tian.addI("a");
    }
}

public class ThreadB extends Thread {
    private Tian tian;
    public ThreadB(Tian tian) {
        super();
        this.tian = tian;
    }
    @Override
    public void run() {
        super.run();
        tian.addI("b");
    }
}
    public static void main(String[] args) {
        Tian tian  = new Tian();
        ThreadA  threadA = new ThreadA(tian);
        threadA.start();
        ThreadB threadB = new ThreadB(tian);
        threadB.start();
    }

上述代码是多个线程同时访问同一个实例对象中的没有同步的方法,
方法内对对象的变量进行的更改,但输出的结果为:

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

不是我们预想的结果,所以出现了“脏读”现象,这就是非线程安全。

要想实现我们预想的结果,就需要对方法进行同步处理,synchronized关键字就
可以同步方法。

eg:
    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();
        }
    }

输出结果为:

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

多个线程方位同一个对象中的同步方法时,一定是线程安全的。

synchronized关键字的简单使用:
当方法被synchronized关键字修饰时,方法就进行了同步处理。当经过同步处理
的方法被多个线程调用时,一个线程开始调用方法就会获得对象锁,这个方法正在
执行,当另一个线程调用该方法时,先去获得对象锁,但对象锁以被上个线程获得,
所以会一直等待获得对象锁而暂停执行,当第一个线程执行完同步方法后,会释放
对象锁,这个时候第二个线程才能获得对象锁,继续执行。也就是说被同步处理的
方法,同一时间只能被一个线程调用。
    public static void main(String[] args) {
        Tian tian  = new Tian();
        ThreadA  threadA = new ThreadA(tian);
        threadA.start();
        Tian tian1 = new Tian();
        ThreadB threadB = new ThreadB(tian1);
        threadB.start();
    }

这个执行结果就是:

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

这个新建了2个对象,两个线程处理了两个对象,是异步的所以不会出现非线程安全。这时多个线程访问多个对象,
jvm会创建多个锁。

注意”共享“,只要出现多个线程使用同一个对象,就要注意线程安全问题

synchronized方法与锁对象及对象方法。规则

1:A线程调用synchronized方法,获得对象锁,B线程仍可通过异步调用该对象的非同步方法。
2:A线程调用synchronized方法,获得对象锁,B线程调用该对象的其他同步方法,仍需等待获得对象锁。
注意:”脏读“ 就是多线程时,对对象变量的赋值和读取,当赋值没有完成,就读取时会出现脏读

synchronized重入锁

就是线程A调用同步方法获得对象锁,可以再次调用该对象的另一个同步方法,再次获得对象锁,也就是对象的同步方法
中可以调用本类的其他同步代码块。 这个属性同样适用与子类同步代码调用父类同步代码块。

线程执行异常时,线程锁自动释放,线程停止。

同步不具有继承性,也就是父类方法有synchronized关键字修饰,是同步方法,但子类重写后不再是同步方法,

synchronized同步语句块

适用同步方法,在一些情况下是很有弊端的,例如,一个线程执行耗时操作时,B线程就需要等待很长时间,这个情况就
可以适用synchronized同步语句块。
public void MyTask{
    private String getData;
    public void doLongTask(){
        try{
            System.out.println("begin task");
            Thread.sleep(30000);
            synchronized(this){  //这里就是synchronized同步语句块。
                getData = priveteData
            }
        }catch (interruptException e){//}
    }
}

这里并没有同步整个方法,而是同步了一部分关键的语句块,这样则避免了同步方法的一些弊端。

注意:synchronized(this)是一个对象监视器,获得该对象的锁,如果已经获得该对象锁,则其他线程对于这个对象的所有synchronized(this)语句块都需要等待。

任意对象做对象监视器。

上面所有介绍的synchronized方法或者synchronized(this)语句块,都是讲该对象本身作为监视器,获得的锁也是
该对象本身的锁,其实我们更改this的内容,就可以将任何对象做为对象监视器。
public class Can{
    private String userName;
    private String anyString = new String();
    public void setUserName(String name){
        synchronized(anyString){
            userName = name;
        }
    }
}

这个锁的对象是anyString ,
注意:
1:该程序获得的是anyString对象锁,如果其他线程要获得该对象中的anyString 对象锁,需要等待。
2:一个对象中可以有多个这样的anyString对象,每一个对象的用法和this一样,线程都是获得的anyString对象的锁,anyString对象锁同时也只能被一个线程获得。
优点如果一个类里有多个同步方法,这样会经常造成线程阻塞,多个对象可以很好解决这个问题

给静态方法上锁

静态方法加synchronized和普通方法加锁效果一致。但静态方法加锁有本质区别,普通方法加锁是获得对象锁,静态
方法加锁是对该类对应的class加锁,也就是说一个是对象锁,一个是class锁。

死锁:死锁必须被避免,死锁就是一个线程获得锁后不能释放,其他线程无法获得锁。

关键字volatile

作用是使变量再多个线程中可见。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值