什么是线程安全
堆内存中的数据由于可以被任何线程所访问,在没有限制的情况下存在被意外修改的风险。即堆内存空间在没有保护机制的情况下,对多线程来说是不安全的,因为放进去的数据可能被别的线程破坏。
如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时执行这段代码,如果多线程运行的结果和单线程运行的结果是一样的,而且其他变量的值和预期也是一样的,就是线程安全的。
编程新说:什么是线程安全-
怎样实现线程安全
一般来说常见的用于保证线程安全的方式有两种- synchronized
synchronized关键字以及和 ReenTrantLock 的对比 - lock(ReenTrantLock )
ReenTrantLock 为Lock的子类private Lock lock = new ReentrantLock(); private void method(Thread thread){ lock.lock(); // 获取锁对象 try { System.out.println("线程名:"+thread.getName() + "获得了锁"); // Thread.sleep(2000); }catch(Exception e){ e.printStackTrace(); } finally { System.out.println("线程名:"+thread.getName() + "释放了锁"); lock.unlock(); // 释放锁对象 } }
- synchronized
synchronized与ReenTrantLock的区别
synchronized关键字以及和 ReenTrantLock 的对比
-
synchronized关键字底层原理
在Java中,每个对象里面隐式的存在一个叫monitor(对象监视器)的对象 。
当monitor对象被线程持有时,Monitor对象中的count就会进行+1,当线程释放monitor对象时,count又会进行-1操作。用count来表示monitor对象是否被持有。
1)monitorenter: monitorenter指令表示获取锁对象的monitor对象,这是monitor对象中的count并会加+1,如果monitor已经被其他线程所获取,该线程会被阻塞住,直到count=0,再重新尝试获取monitor对象
(2)monitorexit: monitorexit与monitorenter是相对的指令,表示进入和退出。执行monitorexit指令表示该线程释放锁对象的monitor对象,这时monitor对象的count便会-1变成0,其他被阻塞的线程可以重新尝试获取锁对象的monitor对象
从synchronized放置的位置不同可以得出,synchronized用来修饰方法时,是通过ACC_SYNCHRONIZED标识符来保持线程同步的。而用来修饰代码块时,是通过monitorenter和monitorexit指令来完成
- volatile关键字的使用