JAVA学习心得-----关于线程安全以及同步监视器(锁)
什么情况下会发生线程安全问题?
当一个数据,被多个并发线程共同操作时,可能会出现线程安全问题。
当线程安全问题发生时,会出现什么情况?
用一个课本上的例子来说,最经典的是售票问题。会出现一票多售或者出现售负票的情况。
出现这种情况,一般是几个线程使用的这个共同数据没有得到及时更新所致。说到这里就需要谈谈线程的生命周期这个问题。画个图来大概表示一下。
线程创建之后,并不会马上运行,会有一个人类感受不到的就绪时间,这之后才会进入运行状态。而运行状态中可能会有事件导致线程阻塞,上图我展示的是因为sleep休眠导致的阻塞。这个时候,另外的线程就会趁机运行,就比如去操作和这个阻塞线程共有的数据。
如何解决这个问题?
使用同步监视器,就是我们常说的锁。
简单的图片例子
例:假设一个程序中,有两个线程1,2,他们具有共同的功能,取出numb值并执行+1操作,最后输出numb的值。‘
下图为无锁状态
无锁时,在线程1发生阻塞的途中,线程2会接管numb值进行加1操作并输出2。然而,线程1阻塞前取到的numb值是1,并不会因为线程2计算完而发生改变,最终也会输出2。最终结果会输出2,2.
接下来表示有锁状态
在数据有锁时,当线程1被阻塞时,线程2使用了数据,这个数据会被更新,线程1会使用线程2更新的数据再进行操作。最终结果会输出2,3.
用程序来说明
思路:线程方法是实现一个数据累加100次,并输出,用两个线程对象同时操作。那么结果应该是从0一直加1,执行200次。
1.首先创建一个存数据的类
public class Data {
public int numb;
}
2.主函数中,创建好对象,两个线程,并给两个线程取名,以便区分线程的操作
public class Text {
public static void main(String[] args) {
//创建共同数据对象
Data a = new Data();
//创建线程对象k1
Threadtext k1 = new Threadtext(a);
k1.setName("线程A");
k1.start();
//创建线程对象k2
Threadtext k2 = new Threadtext(a);
k2.setName("线程B");
k2.start()