多线程之 线程安全
2021-07-08 14:05
标签:关键字 err unlock sleep 成员 zed 其他 tca color 原因: 原本不应该拆开的两个步骤中间,被其他线程插足。 解决方案:(java中的同步机制 [synchronized] 来解决),具体有下面三种 代码演示线程安全问题: 上面代码Demo01TicketTest,运行后可在控制台查看: 1.出现了票 0 ,-1 2.还有售出重复的票 这就是多个线程会出现的线程安全问题,而在现实中这是不允许的 同步代码块: synchronized关键字可以用于方法中的某个区块中,表示支队这个区块的资源实行互斥访问 格式: synchronized( 同步锁 ){ 需要同步操作的代码 } 同步锁: 对象的同步锁知识一个概念,就是个标记,(就好像狮子占地盘,撒了尿这就是我的地盘) 1. 锁对象,可以是任意类型 2. 多个线程对象,要使用同一把锁 注意: 一个同步锁最多被一个线程锁拥有,谁拿到锁就可以进入代码块,其他的线程只能外面等待,等待同步锁被上一个线程释放后,再进行抢占cpu 使用此方法解决,上面多线程售票安全问题 同步方法: 使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外面等着 格式: public synchronized void method(){ 可能会产生线程安全问题的代码 } 注意: 同步方法中也有同步锁 对于非static方法,同步锁就是this, 对于static方法,同步锁是类名.class (我们使用当前方法所在类的字节码对象) 使用同步方法代码解决售票的线程安全问题: Lock锁: lock机制提供了比synchronized代码块和synchronized方法更加广泛的操作 Lock,更加强大,更加体现面向对象 Lock锁也成为同步锁,将加锁和释放所拆分两个方法,如下: public void lock(): 加同步锁 public void unlock(): 释放同步锁 使用该方法解决多线程售票安全问题 多线程之 线程安全 标签:关键字 err unlock sleep 成员 zed 其他 tca color 原文地址:https://www.cnblogs.com/xiangshaui/p/9582483.html一.线程安全出现原因:
a. 同步代码块
b. 同步方法
c. Lock接口
创建:Lock lock = new ReentrantLock();
霸占锁:lock();
释放锁:unlock();public class Ticket implements Runnable{
//定义一个成员变量,表示还有多少张票
int num = 100;
//要在run方法中定义卖票的任务
@Override
public void run() {
//因为要一直卖票,所以使用死循环
while (true) {
//如果还有票,那么就卖票
if(num > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + num);
num--;
}
}
}
}
public class Demo01TicketTest {
public static void main(String[] args) {
//创建三个线程,执行这个卖票任务
Ticket t = new Ticket();
//等同于创建了3个窗口,每个窗口都执行一样的任务:售票
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
二.解决线程安全的同步代码块方法
public class Ticket implements Runnable{
int num = 100;
//定义一个对象,这个对象表示锁对象
//锁对象没有特殊的含义,只是做一个标记
//多个线程必须使用同一个锁对象,否则不能保证线程安全。
Object lock = new Object();
@Override
public void run() {
while (true) {
//当线程执行到synchronized这句代码的时候,会看一下这个上面还有没有锁
//如果同步代码块上面还有锁,那么线程就获取到这个锁, 然后进入到同步代码块中。
//如果同步代码块上面没有锁, 那么这个线程就一直在这个位置等着获取锁, 如果锁一直不来,那么就一直等着.
synchronized (lock) {
if(num > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + num);
num--;
}
}
//当一个线程离开同步代码块,那么他会释放锁。
//之后其他线程就可以去竞争这个锁,谁抢到了,那么谁就去执行这个同步代码块。
}
}
}
三.解决线程安全的同步方法方法
package cn.itcast.demo02;
@SuppressWarnings("all")
public class Ticket implements Runnable{
int num = 100;
@Override
public void run() {
while (true) {
sell();
}
}
//同步方法,表示对整个方法体都加上了同步代码块
public synchronized void sell() {
if(num > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + num);
num--;
}
}
}
四.解决线程安全的Lock接口方法
public class Ticket4 implements Runnable{
int num = 100;
//创建Lock对象
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
//调用lock对象的lock()方法,手动的获取锁
lock.lock();
if(num > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + num);
num--;
}
//调用lock对象的unlock方法,手动的释放锁
lock.unlock();
}
}
}
上一篇:进程和线程的概念