Java那些事儿之线程安全

@线程:

线程安全:所谓的线程安全,就是要控制多个线程对某个资源的有序访问和修改。
保证线程安全的方法:
1.
synchronized关键字用于修饰方法体或者包裹代码快,保证在多线程环境下,未返回结果前只能够被一个线程操作。

       public synchronized void count(){
	}
	synchronized(lock){
	代码块
	}


2. volatile 关键字用于修饰字段。volatile保证内数据的可见性,即保证每次都对主存数据进行操作。
      
         public volatile num = 0;

3.jdk-6以后提供了 Lock 对象。
	Lock lock = new ReentrantLock();
	public void count(){
	    lock.lock();//取得锁
	    代码块
	    lock.unlock();
	}

上面提到的可见性就涉及到java的内存模型问题,要解决内存模型,必须要解决可见性和有序性两个问题。
可见性:在主存内的数据。

int num = 0;
for(int i = 0;i<10;i++){
   num+=1;
}

以上代码中。num存在与主存。当执行num+=2;时jvm先是将num从主存中拷贝一个副本。
之后对num的操作都是在操作副本。至到最后一次同步到主存。因此在数据未同步到主存中时,其他线程
访问主存中的num值就不是我们希望得到的值。这就是可见性问题。说道这里我们就抛出这么一个问题:
“如何控制多线程对数据的有序访问?”
如果我们没有解决同步问题:那么一个共享对象就可以同时被多个线程操作,造成结果混乱。以向一个银行账户存款&取款为例:

package com.zhaofeng;

public class Bank {  
	  
    private int balance;  
  
    public Bank(int balance) {  
        this.balance = balance;  
    }  
  
    public int getBalance() {  
        return balance;  
    }  
  
    public void add(int num) {  
        balance = balance + num;  
    }  
  
    public void out(int num) {  
        balance = balance - num;  
    }  
  
    public static void main(String[] args) throws InterruptedException {  
        Bank account = new Bank(1000);  
        Thread a = new Thread(new AddThread(account, 20000), "存款");  
        Thread b = new Thread(new OutThread(account, 10000), "取款");  
        a.start();  
        b.start();  
        a.join();  
        b.join();  
        System.out.println(account.getBalance());  
    }  
  
    static class AddThread implements Runnable {  
        Bank account;  
        int     amount;  
  
        public AddThread(Bank account, int amount) {  
            this.account = account;  
            this.amount = amount;  
        }  
  
        public void run() {  
            for (int i = 0; i < amount; i++) {  
                account.add(1);  
            }  
        }  
    }  
  
    static class OutThread implements Runnable {  
        Bank account;  
        int     amount;  
  
        public OutThread(Bank account, int amount) {  
            this.account = account;  
            this.amount = amount;  
        }  
  
        public void run() {  
            for (int i = 0; i < amount; i++) {  
                account.out(1);  
            }  
        }  
    }  
}  

以上 代码并未使用同步机制,多次运行,程序会产生不同的结果。所以,多线程对add()和out()的访问也是不可预见的,因此。需要将add()和out()函数用synchronized关键字或是上述其他方法。

 public synchronized void add(int num) {  
        balance = balance + num;  
    }  
  
    public synchronized void out(int num) {  
        balance = balance - num;  
    }  
这样就保证了多线程的有序访问。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值