学习过操作系统原理同学们都知道,当多个线程或者进程访问共享数据,也就是说临界资源的时候会导致程序的可再现性失效。 在程序中,多线程同时运行相同代码块,也就是说多个线程对全局变量,静态变量进行写操作的时候,都会产生安全问题。
还记的当初我们是如何解决线程该类问题的吗?同步机制,整型信号量机制,信号量机制,以及AND型信号量机制,是否想起PV操作?
例子:电影院今天卖电影票100张,三个窗口都卖,会出现怎样的结果呢?
public class DemoRunnable implements Runnable {
public int ticket=100;
@Override
public void run() {
//循环卖票过程
while(true){
//判断是否还有票
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"→正在卖第"+ticket +"票");
ticket--;
}
}
}
}
public class MIanRunnable {
public static void main(String[] args){
//创建Runnable接口实现类对象
DemoRunnable r=new DemoRunnable();
//创建Thread对象,构造方法中传递Runnable接口实现类对象
Thread t0=new Thread(r,"0号窗口");
Thread t1=new Thread(r,"1号窗口");
Thread t2=new Thread(r,"2号窗口");
//调用start()方法开始多线程
t0.start();
t1.start();
t2.start();
}
}
个别结果:
2号窗口→正在卖第1票
1号窗口→正在卖第0票
0号窗口→正在卖第-1票
0号窗口→正在卖第22票
2号窗口→正在卖第22票
1号窗口→正在卖第22票
通过结果我们发现,不同的窗口可以卖重复票,以及可以卖负票。显然是不符合常理的。这就是线程安全问题,多个线程访问同一个资源的时候,且这多个线程对资源进行写操作的时候,就会出现线程安全问题。
出现问题的原因,多个线程,同时对同一资源(此处指全局变量ticket)进行写操作,所以任意一个时刻,只能有一个线程对资源进行访问,才能解决该类问题。
①同步代码块:synchronized 关键字,用于方法中某一块代码,表示该块代码的资源实行互斥访问。
//全局变量共享票
public int ticket = 100;
//创建一个锁对象
Object obj = new Object();
@Override
public void run() {
//循环卖票过程
while (true) {
//同步代码块
synchronized (obj) {
//判断是否还有票
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
"→正在卖第" + ticket + "张票");
ticket--;
}
}
}
}
}
②同步方法,用synchronized关键字修饰的方法,某一线程执行该方法,其他线程处于阻塞态
public class synchronize implements Runnable {
//共享票
public int ticket = 100;
@Override
public void run() {
Ticket();
}
public synchronized void Ticket(){
//循环卖票过程
while (true) {
//同步代码块
//判断是否还有票
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
"→正在卖第" + ticket + "张票");
ticket--;
}
}
}
}
③Lock锁,也可以叫做同步锁,存在加同步锁和释放同步锁的方法
public class lock implements Runnable {
//共享票
public int ticket = 100;
//成员位置创建一个ReetrantLock锁
Lock l=new ReentrantLock();
@Override
public void run() {
Ticket();
}
public synchronized void Ticket(){
//循环卖票过程
while (true) {
//在可能出现问题的代码前调用LOck接口中的方法Lock获取锁
l.lock();
//判断是否还有票
if (ticket > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() +
"→正在卖第" + ticket + "张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
//无论程序异常都会释放锁
//在可能出现问题的代码后调用LOck接口中的方法unLock获取锁
l.unlock();
}
}
}
}
}
关于Java多线程解决方案,就先分享到这里,内容不是很详细,但是很实用,有待完善!
本文探讨了Java中多线程环境下线程安全问题的根源,并介绍了三种解决方法:使用synchronized关键字创建同步代码块或同步方法,以及利用Lock锁进行资源访问控制,确保在并发场景下数据的一致性和完整性。
1157





