线程安全
Posted wurengen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全相关的知识,希望对你有一定的参考价值。
什么是线程安全?
如果多个线程同时运行,而这些线程都访问了共享数据。程序每次运行的结果和单线程运行的结果都是一样的。而其他的变量的值和预期的是一样的,这就是线程安全。如果产生的结果和预期的不一样,这样的问题,我们就称之为线程安全问题。线程安全问题都是由全局变量和静态变量引起的。
如何解决线程安全问题?
线程安全问题是不能产生的,我们可以让一个线程在访问,操作共享数据的时候,无论是否失去了cpu的执行权,让其他的线程只能等待,等待当前线程是否了对共享数据的访问。其他线程才能访问,操作共享数据。为了解决线程安全问题。Java中提供了同步机制(synchronized)解决。要怎么样使用?
有下面三种方式:
- 方式一:同步代码块
格式:
synchronized(锁对象){
//可能出现线程安全的代码块(访问了共享数据的对象)
}
注意:
- 通过代码块中的锁对象,可以使用任意的对象
- 多个线程必须使用的是同一个锁对象
- 锁对象的作用:只让一个线程在
代码举例
public class Ticket implements Runnable { //设置票总数 private int ticket = 25; Object object = new Object(); @Override public void run() { // 不停的卖票 while (true) { //判断票是否存在 synchronized (object) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //存在就卖票 System.out.println(Thread.currentThread().getName() + "正在卖" + ticket + "票"); ticket--; } } } } }
同步技术的原理:
在任何的时候,最多允许一个线程拥有同步锁,谁拿到同步锁就进入代码块,其他的线程只能在外面等着。
- 方式二:同步方法
使用synchronized修饰的方法,叫做同步方法。保证一个线程执行该方法的时候,其他的线程在方法外等着
格式:
使用步骤:
- 把访问了共享数据的代码抽取出来,放在一个方法中
- 在方法上添加修饰符synchronized
代码举例
package demo02; public class Ticket implements Runnable { //设置票总数 private int ticket = 25; @Override public void run() { // 不停的卖票 while (true) { //判断票是否存在 method(); } } public synchronized void method() { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //存在就卖票 System.out.println(Thread.currentThread().getName() + "正在卖" + ticket + "票"); ticket--; } } }
此方式实现也是 利用了同步锁:
- 方式三:Lock锁
java.util.concurrent.locks.Lock 机制,不但具有同步代码块和同步方法具有的功能。 而且更加强大,更能体现面向对象。
Lock锁也称之为同步锁,加锁与释放锁的方法如下:
- public void lock ():加同步锁
- public void unlock():释放同步锁
使用步骤:
- 因为lock是接口,所以第一步要在成员变量位置获取他的实现类对象ReentrantLock对象
- 在可能出现安全问题的代码前调用Lock接口中的方法lock获取锁
- 在可能出现安全问题的代码后调用Lock接口中的方法unlock释放锁
代码举例:
package demo02; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Ticket implements Runnable { //设置票总数 private int ticket = 25; // 多态获取子类对象 Lock lock = new ReentrantLock(); @Override public void run() { // 不停的卖票 while (true) { // 获取锁 lock.lock(); //判断票是否存在 if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //存在就卖票 System.out.println(Thread.currentThread().getName() + "正在卖" + ticket + "票"); ticket--; } //释放锁 lock.unlock(); } } }
以上是关于线程安全的主要内容,如果未能解决你的问题,请参考以下文章
HashMap 和 ConcurrentHashMap 的区别
newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段