疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java线程安全


 

       @线程:

  线程安全:所谓的线程安全,就是要控制多个线程对某个资源的有序访问和修改。

  保证线程安全的方法:

  1.synchronized关键字用于修饰方法体或者包裹代码快,保证在多线程环境下,未返回结

  果前只能够被一个线程操作。

  [java]

  public synchronized void count(){

  }

  synchronized(lock){

  代码块

  }

  2.volatile关键字用于修饰字段。volatile保证内数据的可见性,即保证每次都对主存数

  据进行操作。

  [java] view plaincopyprint?在CODE上查看代码片派生到我的代码片

  public volatile num = 0;

  3.jdk-6以后提供了Lock对象。

  [java]

  Lock lock = new ReentrantLock();

  public void count(){

  lock.lock();//取得锁

  代码块

  lock.unlock();

  }

  上面提到的可见性就涉及到java的内存模型问题,要解决内存模型,必须要解决可见性和

  有序性两个问题。

  可见性:在主存内的数据。

  [java]

  int num = 0;

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

  num+=1;

  }

  以上代码中。num存在与主存。当执行num+=2;时jvm先是将num从主存中拷贝一个副本。

  之后对num的操作都是在操作副本。至到最后一次同步到主存。因此在数据未同步到主存

  中时,其他线程

  访问主存中的num值就不是我们希望得到的值。这就是可见性问题。说道这里我们就抛出

  这么一个问题:

  “如何控制多线程对数据的有序访问?”

  如果我们没有解决同步问题:那么一个共享对象就可以同时被多个线程操作,造成结果混

  乱。以向一个银行账户存款&取款为例:

  [java]

  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关键字或是上述其他方法。

  [java]

  public synchronized void add(int num) {

  balance = balance + num;

  }

  public synchronized void out(int num) {

  balance = balance - num;

  }

  这样就保证了多线程的有序访问。