线程安全:当程序多个并发线程同时访问一个目标或者资源时,对其最终所产生结果的正确性不会造成影响的情况下,就是所说的线程安全。
线程不安全:多个线程同时访问一个目标或资源的时候,随着线程的访问进行,在某种情况下会造成最终结果的改变,这就是所说的线程不安全
实现和预防线程安全的方法:
1.减少多线程访问对象的全局变量的引用
对全局变量进行操作的方法在多线程访问的情况下会造成结果的更改不能及时的得到验证和反馈,最终造成预期结果的改变 ,如下:
启动1000个线程对含有全局变量的方法进行并发访问:
import javax.jws.WebParam;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,//核心线程数量
1000,//最大线程数量限制
3,//空闲等待时间(非核心线程到达时间还处于空闲状态将被回收)
TimeUnit.SECONDS,//keepAliveTime 量化单位
new ArrayBlockingQueue<Runnable>(2));//等待线程队列
ModelClass modelClass=new ModelClass();
for (int i = 0; i < 1000; i++) {
executor.execute(new ThreadTest(modelClass));
}
executor.shutdown();
}
//线程类
static class ThreadTest implements Runnable {
//引用方法所在类
ModelClass modelClass;
public ThreadTest(ModelClass modelClass) {
this.modelClass = modelClass;
}
@Override
public void run() {
modelClass.getCount();
}
}
static class ModelClass {
public int x =1000;//全局变量
public void getCount() {
System.out.println(--x);
}
}
}
结果:
注意:在多线程并发访问中,随着并发线程总量的不断增加,线程的安全性是逐步下降的
2.使用关键字 synchronized
线程的锁机制原理为,相同的目标和方法在添加synchronized关键字后,只允许同一时间的单个线程进行拥有访问执行,在当前线程执行完之后才会解锁供后面的线程使用,也就是说在多线程访问的时候在synchronized 处线程形成等待队列,而不是根据cpu分配资源进行自由的访问执行
代码:
在方法声明部分加上synchronized
static class ModelClass {
public int x =1000;
public synchronized void getCount() {//添加锁机制,只允许单线程同步执行,后来线程等待
System.out.println(--x);
}
}
结果:
上面这种形式在方法内容相对简单时使用还可以,当方法体内容丰富,执行效率会很低,所以可以在方法体中进行部分内容锁定 如下:
static class ModelClass {
public int x =1000;
public void getCount() {
synchronized(this){//方法体部分锁定
System.out.println(--x);
}
}
}
3.使用Lock
static class ModelClass {
public int x =1000;
Lock lock=new ReentrantLock();
public void getCount() {
lock.lock();//锁定
System.out.println(--x);
lock.unlock();//解锁
}
}