线程安全问题
为什么会产生线程安全问题?
程序中有多个线程在线操作共享数据,当有多个线程对于同一个数据进行在线操作时,由于线程抢占CPU的机制,被操作的数据可能会产生冲突,即产生多线程的安全问题。
线程安全的定义:如果线程执行过程中不会产生共享资源的冲突就是线程安全的。
保证线程安全的方法:
1.关键字 synchronized 同步代码块
2.同步方法
3.ReentrantLock
4.volatile
同步代码块:
同步代码块的示例:
synchronized(this){
//共享数据.....
}
其中的 this 可以替换成其他的同步监视器(锁),若两个或多个线程有着同样的同步监视器(锁),那么同步代码块内部的共享数据就会保证线程安全,一次只能执行一个线程的进程,这样就保证了多个线程对共享数据的操作是安全的,不会产生冲突,做到了线程安全。
同步方法:
同步方法的示例:
public synchronized void test() {
//共享数据.....
}
与同步代码块类似,同步方法也使用了 synchronized 关键字。
当用此同步方法时,内置锁会保护整个方法,让整个方法成为同步方法,在多个线程同时对于同步方法内的共享数据进行操作时,不会产生冲突,保证了线程安全。
ReentrantLock
Lock锁机制的基本语法:
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
示例:
try{
lock.lock();
//......
}
finally{ //结束后一定会执行
lock.unlock();
}
Lock锁机制是通过创建Lock对象,通过 lock() 加锁和 unlock() 解锁来保护指定的代码块,实现线程安全。
如代码块所示,使用Lock锁机制时,系统无法自动解锁,因此需要我们在 finally 语句中对于已经创建过的 Lock 对象进行 unlocck() 解锁操作来释放锁。
线程安全的优点与缺点
优点:
在多个线程同时对于共享数据进行操作时可能会产生冲突的情况,得不到预想的结果,而如果通过同步监听器等方法保证了线程安全,可以避免多个线程在同时运行时的产生的冲突情况,即不能同时进行操作共享的数据,保证了线程内共享数据的安全性。
缺点:
我们使用线程的目的是为了让多个线程同时进行,提高我们的程序运行速度,但是使用了同步监听器等方法对线程加锁,虽然保证了线程安全,但是加锁的线程在同一时刻只能有一个在运行中,这样就达不到提高程序运行效率的目的,因此我们在考虑线程安全问题时,对于是否对一个线程加上同步监听器应该慎重考虑到程序的安全性和效率等多方面问题。