赞
踩
我们在开发中直接使用线程是无法保证线程安全的,有可能出现多个线程先后更改数据造成所得到的数据是脏数据,那么怎么解决这种问题呢,就要应用到线程安全的三种解决方法了
线程安全: 如果有多个线程在同时运行,而这些线程可能会同时运行某段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的
线程不安全: 当有多个线程在同时运行,这些线程同时运行一段代码(同一段任务代码,同一个run方法),操作同一个共享数据时, 这时候可能就会出现线程的安全问题,即线程不安全的.,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
1.举例说明线程不安全
Ticket
任务类/** * @Description * @auther 宁宁小可爱 * @create 2020-01-10 14:29 */ public class Ticket implements Runnable { // 总共一百张票 private int ticket = 100; /* * 执行卖票操作 * */ @Override public void run() { // 窗口永远卖票 while (true){ if (ticket > 0){ try { // 使用sleep模拟出票流程 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 获取当前线程的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在卖: " + ticket--); } } } }
/** * @Description * @auther 宁宁小可爱 * @create 2020-01-10 14:33 */ public class TicketDemo { public static void main(String[] args) { Ticket ticket = new Ticket(); Thread t1 = new Thread(ticket,"窗口一"); Thread t2 = new Thread(ticket,"窗口二"); Thread t3 = new Thread(ticket,"窗口三"); t1.start(); t2.start(); t3.start(); } }
发现程序出现了两个问题,这就是线程不安全造成的
线程安全问题都是对全局变量及静态变量的修改引起的。若每个线程中对全局变量、静态变量只有读操作, 而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题,那么我们怎么解决线程安全问题呢? 答案很简单,使用线程同步即可
线程同步: 使线程按照一定的先后次序进行运行
线程同步有三种方式:
synchronized
关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问// 同步代码块格式
synchronized(同步锁){
需要同步操作的代码
}
使用同步代码块解决代码问题:
/** * @Description * @auther 宁宁小可爱 * @create 2020-01-10 14:29 */ public class Ticket implements Runnable { // 总共一百张票 private int ticket = 100; // 创建锁对象 Object lock = new Object(); /* * 执行卖票操作 * */ @Override public void run() { // 窗口永远卖票 while (true){ // 同步代码块 synchronized (lock){ if (ticket > 0){ // 这里把sleep去掉运行结果更明显 // 获取当前线程的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在卖: " + ticket--); } } } } }
同步方法: 使用synchronized
修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着
// 同步方法格式
public synchronized void method(){
可能会产生线程安全问题的代码
}
同步锁是谁?
使用同步方法解决代码问题:
/** * @Description * @auther 宁宁小可爱 * @create 2020-01-10 14:29 */ public class Ticket implements Runnable { // 总共一百张票 private int ticket = 100; /* * 执行卖票操作 * */ @Override public void run() { // 窗口永远卖票 while (true){ sellTicket(); } } // 把存在线程安全问题的代码放入同步方法中 public synchronized void sellTicket(){ if (ticket > 0){ // 获取当前线程的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在卖: " + ticket--); } } }
java.util.concurrent.locks.Lock
机制提供了比synchronized
代码块和synchronized
方法更广泛的锁定操作, 同步代码块/同步方法具有的功能Lock
都有,除此之外更强大,更体现面向对象。
Lock锁也称同步锁,加锁和释放锁方法如下:
public void lock()
public void unlock()
使用lock锁解决代码问题:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description * @auther 宁宁小可爱 * @create 2020-01-10 14:29 */ public class Ticket implements Runnable { // 总共一百张票 private int ticket = 100; // 创建锁对象 Lock lock = new ReentrantLock(); /* * 执行卖票操作 * */ @Override public void run() { // 窗口永远卖票 while (true){ // 同步代码块 加锁 lock.lock(); if (ticket > 0){ // 获取当前线程的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在卖: " + ticket--); } // 释放锁 lock.unlock(); } } }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。