共享变量 (Volatile Atomic)
volatile:当多个线程访问一个成员变量的时候,需要这个变量在多个线程中可见。
Atomic:Atomic方法对该变量的操作是原子性操作,颗粒度是到对这个变量的一次操作。
private static AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
Atomic+synchronized :如果要保证多线程之间的原子性操作,也就是对一个变量进行多次Atomic方法操纵操作。那就需要加synchronized ,来 保证多线程间的原子性。
private static AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
count.incrementAndGet();
count.incrementAndGet();
//多线程间他们不是原子性操作,如果需要原子性操作,需要在外层方法加synchronized
Volatile
原理:当线程操作该变量的时候会强制去主内存(堆)中去读取。使用方法如下
public class RunThread extends Thread{
private volatile boolean isRunning = true;
private void setRunning(boolean isRunning){
this.isRunning = isRunning;
}
public void run(){
System.out.println("进入run方法..");
int i = 0;
while(isRunning == true){
//..
}
System.out.println("线程停止");
}
public static void main(String[] args) throws InterruptedException {
RunThread rt = new RunThread();
rt.start();
Thread.sleep(1000);
rt.setRunning(false);
System.out.println("isRunning的值已经被设置了false");
}
}
volatile 变量本身不具备原子性。说明
public class VolatileNoAtomic extends Thread{
private static volatile int count;
private static void addCount(){
for (int i = 0; i < 1000; i++) {
//count++ ;
count.incrementAndGet();
}
System.out.println(count);
}
public void run(){
addCount();
}
public static void main(String[] args) {
VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
for (int i = 0; i < 10; i++) {
arr[i] = new VolatileNoAtomic();
}
for (int i = 0; i < 10; i++) {
arr[i].start();
}
}
Atomic
如果要实现原子性(同步),可以使用Atomic类型的变量。如AtomicInteger、AtomicLong…
private static AtomicInteger count = new AtomicInteger(0);
但是,只能保证方法的原子性,不能保证多线程间的原子性。解决方法可以给方法synchronized 修饰,加说明
private static AtomicInteger count = new AtomicInteger(0);
//多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
/**synchronized*/
public synchronized int multiAdd(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.addAndGet(1);
count.addAndGet(2);
count.addAndGet(3);
count.addAndGet(4); //+10
return count.get();
}
public static void main(String[] args) {
final AtomicUse au = new AtomicUse();
List ts = new ArrayList();
for (int i = 0; i < 100; i++) {
ts.add(new Thread(new Runnable() {
@Override
public void run() {
System.out.println(au.multiAdd());
}
}));
}
for(Thread t : ts){
t.start();
}
ThreadLocal
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。用ThreadLocal可以一定程度减少锁竞争。使用方式如下
public class ConnThreadLocal {
public static ThreadLocal th = new ThreadLocal();
public void setTh(String value){
th.set(value);
}
public void getTh(){
System.out.println(Thread.currentThread().getName() + ":" + this.th.get());
}
public static void main(String[] args) throws InterruptedException {
final ConnThreadLocal ct = new ConnThreadLocal();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ct.setTh("张三");
ct.getTh();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
ct.getTh();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t2");
t1.start();
t2.start();
}
}