JAVA 线程同步机制
作者:互联网
线程安全问题:
当多个线程共享一批数据时,则会出现线程安全问题,看个demo
三个线程 同时卖100张票,此时运行则会出现线程安全问题,运行结果可能会出现卖重复的张数,或者卖不出现的张数。
public class Runnable2 implements Runnable {
private int ticket = 100;//票数
@Override
public void run() {
while (true){
if(ticket > 0 ){
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
ticket--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Runnable2 r2 = new Runnable2();
Thread t1 = new Thread(r2);
Thread t2 = new Thread(r2);
Thread t3 = new Thread(r2);
t1.start();
t2.start();
t3.start();
}
}
线程安全问题产生的原理:
重复现象是因为 当多个线程同时执行了System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); 此时还没有进行 ticket--,所以会出现重复现象。
出现不该出现的张数是因为 多个线程同时进入if语句 当ticket--为0时,此时ticket为-1,if条件不符合,但此时还有线程在if语句里面,当此线程再执行时就是打印出ticket为-1。
解决线程安全问题:
① 使用同步代码块 先创建一个锁对象 在编写一同步代码块 synchronized(锁对象){可能会出现线程安全的代码} 同步中的线程没有执行完毕不会释放锁,同步外的线程没有锁进不去同步 此方法的缺点就是会降低效率
public class Runnable2 implements Runnable {
private int ticket = 100;//票数
Object obj = new Object(); //创建锁对象
@Override
public void run() {
while (true) {
//创建一个同步代码块
synchronized (obj) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
②使用同步方法
同步方法同样也会把代码锁住 ,让一个线程执行 同步方法的锁对象就是默认的实现类对象(this)
@Override
public void run() {
while (true) {
//调用方法
payTicket();
}
}
//创建一个同步方法
public synchronized void payTicket(){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
补充:使用静态方法 此时的锁对象不能再是 this 而是本类的class属性
③使用LOCK锁 使用LOCK 要比 synchronize更为灵活 首先创建一个ReentrantLock锁对象 再在代码前加上lock()方法加上锁
最后使用unlock()方法来释放锁。
public class Runnable3 implements Runnable {
private int ticket = 100;//票数
//创建一个ReentrantLock锁对象
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
//开启锁
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
}
}
标签:同步,JAVA,Thread,张票,线程,ticket,public 来源: https://blog.csdn.net/qq_42183409/article/details/94658399