1)停止线程的运行
Thread类中的stop方法可以停止线程的运行,但是该方法已经被弃用了,一般会采用改变对象中的一个标识的方法来停止线程的运行或者使用interrupt方法来中断线程
例如:
public class VolatileTest extends Thread{
private boolean stop;
public void isStop(boolean stop){
this.stop = stop;
}
public void run() {
while(!stop){
System.out.println("hello");
}
}
public static void main(String[] args) {
VolatileTest t = new VolatileTest();
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.isStop(true);
System.out.println("main线程结束");
}
}
2)JVM对代码的执行优化
JVM启动的时候有俩种模式:-server和-client,在第一章的课程里已经介绍过了,其中-server模式下JVM会对热点代码使用JIT编译器以及进行代码优化,所以会出现下面的情况:
例如:
public class VolatileTest extends Thread{
private boolean stop;
public void isStop(boolean stop){
this.stop = stop;
}
public void run() {
int a = 0;
while(!stop){
a++;
}
System.out.println("a = "+a);
}
public static void main(String[] args) {
VolatileTest t = new VolatileTest();
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.isStop(true);
System.out.println("main线程结束");
}
}
注:观察执行结果发现,启动的新线程并不能被停止(注意主线程睡眠时间)
3)产生以上问题的原因
程序入口被执行之后,变量stop及其值是在堆区之中(主内存),新的线程启动运行之后,把堆区中的stop读取并加载到了线程的工作内存之中,虽然t.isStop(true)代码被调用了,但是这只是把主内存中的stop的值给设置为true了,线程工作内存中的stop的值却依然是false,这其实就是主内存和线工作内存中的值不一致造成的。这也是在-server模式下,JVM对代码进行优化提高了代码的执行效率而带来的一些问题。
4)以上问题的解决方案
1.使用synchronized给循环中的代码加锁
例如:
public void run() {
int a = 0;
while(!stop){
synchronized (this) {
a++;
}
}
System.out.println("a = "+a);
}
注:如果synchronized加锁是加在了while外面,则不能达到想要的效果
思考:为什么以上例子中的run方法中如下编写即可停止线程
public void run() {
while(!stop){
System.out.println("hello");
}
}
2.使用volatile关键字
例如:
public class VolatileTest extends Thread{
private volatile boolean stop;
public void isStop(boolean stop){
this.stop = stop;
}
public void run() {
long a = 0;
while(!stop){
a++;
}
System.out.println("a = "+a);
}
public static void main(String[] args) {
VolatileTest t = new VolatileTest();
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.isStop(true);
System.out.println("main线程结束");
}
}
注:从运行结果打印出的数字,可以看到volatile比使用synchronized关键字的效果要高很多。
5)volatile关键字
关键字volatile的作用是强制线程从公共堆栈(主内存)中取得变量的值,而不是从线程私有数据栈中取得变量的值
下面将关键字volatile和synchronized进行比较:
1.关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,而synchronized可以修饰方法和代码块。随着JDK版本的提高,synchronized关键字在执行效率上得到很大提升,在开发中使用synchronized关键字的比率还是比较大的
2.多线程程序中访问到volatile不会发生阻塞,而synchronized会出现阻塞
3.volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它也会将线程工作内存和主内存中的数据做同步,但效率比volatile低
注:下面会有例子说明这个原子性的问题
4.关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的多个线程之间访问资源的同步性。