文章目录
- 临界资源
- 线程安全
- 基本概念
- *何谓竞态条件*
- *何谓线程安全*
- 对象的安全
- 局部基本类型变量
- 局部的对象引用
- 对象成员(成员变量)
- 不可变性
临界资源
临界资源是一次仅允许一个进程使用的共享资源。各进程采取互斥的方式,实现共享的资源称作临界资源。属于临界资源的硬件有,打印机,磁带机等;软件有消息队列,变量,数组,缓冲区等。诸进程间采取互斥方式,实现对这种资源的共享。
线程安全
基本概念
何谓竞态条件
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。
导致竞态条件发生的代码区称作临界区。
在临界区中使用适当的同步就可以避免竞态条件,如使用synchronized或者加锁机制。
何谓线程安全
允许被多个线程同时执行的代码称作线程安全的代码。线程安全的代码不包含竞态条件。
对象的安全
局部基本类型变量
局部变量存储在线程自己的栈中。也就是说,局部变量永远也不会被多个线程共享。所以,基础类型的
局部变量是线程安全的。下面是基础类型的局部变量的一个例子:
public class ThreadTest {public static void main(String[]args){MyThread share = new MyThread();for (int i=0;i<50;i++){new Thread(share,"线程"+i).start();}}
}
class MyThread implements Runnable{public void run() {int a =0;++a;System.out.println(Thread.currentThread().getName()+":"+a);}
}
无论多少个线程对run()方法中的基本类型a执行++a操作,只是更新当前线程栈的值,不会影响其他线程,也就是不共享数据;
局部的对象引用
对象的局部引用和基础类型的局部变量不太一样,尽管引用本身没有被共享,但引用所指的对象并没有存储在线程的栈内。所有的对象都存在共享堆中。
如果在某个方法中创建的对象不会逃逸出(即该对象不会被其它方法获得,也不会被非局部变量引用到)该方法,那么它就是线程安全的。
实际上,哪怕将这个对象作为参数传给其它方法,只要别的线程获取不到这个对象,那它仍是线程安全的。
public void method1(){LocalObject localObject = new LocalObject();localObject.callMethod();method2(localObject);
}
public void method2(LocalObject localObject){localObject.setValue("value");
}
对象成员(成员变量)
对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是线程安全的。
public class ThreadTest {public static void main(String[]args){NotThreadSafe sharedInstance = new NotThreadSafe();new Thread(new MyRunnable(sharedInstance)).start();new Thread(new MyRunnable(sharedInstance)).start();}
}
class MyRunnable implements Runnable{NotThreadSafe instance = null;public MyRunnable(NotThreadSafe instance){this.instance = instance;}public void run(){this.instance.add(" "+Thread.currentThread().getName());System.out.println(this.instance.builder.toString());}
}
class NotThreadSafe{StringBuilder builder = new StringBuilder();public void add(String text){this.builder.append(text);}
}
不可变性
通过创建不可变的共享对象来保证对象在线程间共享时不会被修改,从而实现线程安全。如下示例:
public class ImmutableValue{private int value = 0;public ImmutableValue(int value){this.value = value;}public int getValue(){return this.value;}
}
请注意ImmutableValue类的成员变量 value 是通过构造函数赋值的,并且在类中没有set方法。这意味着一旦ImmutableValue实例被创建, value 变量就不能再被修改,这就是不可变性。但你可以通过getValue()方法读取这个变量的值。