实例变量与线程安全
自定义线程类中的实例变量针对其他线程可以有共享与不共享之分,这在多个线程之间进行交互时是很重要的一个技术点。
一 、不共享数据的情况
public class MyThread extends Thread {
private int count = 5 ;
public MyThread(String name) {
super();
this.setName(name);
}
@Override
public void run() {
super.run();
while (count > 0) {
count--;
System.out.println("由 " + this.currentThread().getName() + " 计算,count=" + count);
}
}
}
public class Run {
public static void main(String[] args) {
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
MyThread c = new MyThread("C");
a.start();
b.start();
c.start();
}
}
‘
以上可以看出,一共创建3个线程,每个线程都有各自的count变量,自己减少自己的count变量的值,也就是变量不共享的情况
二 、不共享数据的情况
public class MyThread extends Thread {
private int count = 5 ;
@Override
public void run() {
super.run();
count--;
System.out.println("由 " + this.currentThread().getName() + " 计算,count=" + count);
}
}
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread a = new Thread(myThread,"A");
Thread b = new Thread(myThread,"B");
Thread c= new Thread(myThread,"C");
Thread d = new Thread(myThread,"D");
Thread e = new Thread(myThread,"E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
发现3有两个线程同时打印,我们想要看的结果没有重复的,而是依次递减的,从而发生了非线程安全的问题。
其实在JVM中,i -- 的操作是分为3步的
- 取得原有的i 值;
- 计算i-1;
- 对i 进行赋值
如果有多个线程同时访问自然出现非线程安全问题。在上面的MyThread类 的run方法中加个关键字synchronized。再试试
public class MyThread extends Thread {
private int count = 5 ;
@Override
synchronized public void run() {
super.run();
count--;
System.out.println("由 " + this.currentThread().getName() + " 计算,count=" + count);
}
}
线程已经安全了。
synchronized可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或者“临界区”。加上它的作用其实就是给方法上了锁,当一个线程执行这个方法时,其实就是得到了这把锁,其他线程就不会进来,等拿到锁的这个线程执行完了,其他线程才会抢这把锁,当然也包括前面那个已经运行完的线程。