多线程编程笔记2
volatile关键字,用于修饰变量,确保变量的可见性,例如如下代码
public class PrintString implements Runnable {
private boolean isCoutinuePrint = true;
public boolean isContinuePrint(){
return isCoutinuePrint;
}
public void setisCountinuePrint(boolean isCountinuePrint){
this.isCoutinuePrint = isCountinuePrint;
}
public void printStringMethod(){
while(isCoutinuePrint){
System.out.println("run printStringMethod thread name="+Thread.currentThread().getName());
}
}
public void run(){
printStringMethod();
}
public static void main(String[] args){
PrintString PrintStringServlce = new PrintString();
new Thread(PrintStringServlce).start();
System.out.println("线程即将停止");
PrintStringServlce.setisCountinuePrint(false);
}
}
isContinuePrint存在于公共堆栈以及线程的私有堆栈中,线程为了效率有可能会一直在私有堆栈中取得该值
而setisContinuePrint()方法尽管被执行,更新的确实公共堆栈中的isCountinuePrint(),有可能会造成死循环
这是可以使用volatile关键字来修饰变量,他的作用是当线程访问isContinuePrint时,强制从公共堆栈取值
即增加了实例变量在多个线程之间的可见性
与synchronized关键字的比较
1.volatile是线程同步的轻量级实现,所以volatile性能比synchronized关键字好
2.volatile关键字只能修饰变量,synchronized关键字可以修饰方法和代码块
3.多线程访问volatile修饰的变量不会阻塞,即不能保证原子性,而synchronized能保证原子性,多线程访问会阻塞
最大的不同.volatile解决的是变量在多个线程之间的可见性,而synchronized解决的是多个线程之间访问资源的同步性
AtomicInteger原子类的使用
原子类能保证没有其他线程能中断或检查正在原子操作中的变量,它在没有锁的情况下可以保证线程安全,例如如下代码
public class AtomicIntegerTest extends Thread{
private AtomicInteger count = new AtomicInteger(0);
public void run(){
for(int i = 0; i< 10000;i++){
System.out.println(count.incrementAndGet()+"先加1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count.addAndGet(100)+"再加100");
}
}
public static void main(String[] args) {
AtomicIntegerTest a = new AtomicIntegerTest();
Thread t1 = new Thread(a);
t1.start();
Thread t2 = new Thread(a);
t2.start();
Thread t3 = new Thread(a);
t3.start();
Thread t4 = new Thread(a);
t4.start();
}
}
不加这一句代码System.out.println(count.addAndGet(100)+"再加100");的时候能正常的累加到10000,说明原子类保证了线程安全
但是方法和方法之间的调用并不是线程安全的,加上上述代码后,加1和加100应该是交替执行,但是不是
用synchronized修饰方法可以让线程安全