因为临界资源没有互斥访问导致的问题,操作系统已经学习的比较详细了,我不再赘述。
就拿老师讲的售票员卖票这个例子来简单叙述一下。
package sourceconflict;
public class SourceConfilct {
//临界资源问题
public static void main(String[] args) {
Runnable r = ()->{
while(TicketCenter.restCount > 0) {
System.out.println(Thread.currentThread().getName() + "卖出一张票" + -- TicketCenter.restCount + "张");
}
};
Thread t1 = new Thread(r, "售票员1");
Thread t2 = new Thread(r, "售票员2");
Thread t3 = new Thread(r, "售票员3");
Thread t4 = new Thread(r, "售票员4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketCenter{
public static int restCount = 100; //剩余票数
}
结果:
可以看到当切换线程的时候,结果不正确。
原因是多个线程并行执行,而线程中的语句并不是原子操作,可能刚刚判断完剩余票数大于0,CPU就被其他的线程抢走,当再次切换到这个线程的时候,剩余票数已经被其他线程更改的面目全非,此时再将其输出,便不是我们期望的结果了。
可以利用同步代码段来解决这个问题。
package sourceconflict;
public class SynchronizedDemo {
public static void main(String[] args) {
Runnable r = ()->{
while(TicketCenter.restCount > 0) {
synchronized ("") {
if(TicketCenter.restCount > 0)
System.out.println(Thread.currentThread().getName() + "卖出一张票" + -- TicketCenter.restCount + "张");
}
}
};
Thread t1 = new Thread(r, "售票员1");
Thread t2 = new Thread(r, "售票员2");
Thread t3 = new Thread(r, "售票员3");
Thread t4 = new Thread(r, "售票员4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行结果:
线程在进入临界区之前,先检查是否上锁,如果上锁则等待临界区中的线程退出后再进入,等待中的线程在锁池里面;如果没有上锁则直接进入临界区,并更改锁标记。
锁里面的内容:
可以用对象,作为对象锁(对象,自定义的字符串),像例子中的synchronized ("") ,就是一个自定义的字符串作为锁。
可以用类,作为类锁(传一个类,如:SynchronizedDemo.class)
同步方法,也就是这个方法中的所有逻辑都需要同步,则将它封装到同步方法中。
如果是静态方法,同步锁是 类锁 当前类.class
如果是非静态方法,同步锁是 this
利用显式锁互斥的访问临界资源:
package sourceconflict;
import java.util.concurrent.locks.ReentrantLock;
public class LockDemo {
public static void main(String[] args) {
/*
* 实例化了一个锁对象
*/
ReentrantLock lock = new ReentrantLock();
Runnable r = ()->{
while(TicketCenter.restCount > 0) {
lock.lock();
if(TicketCenter.restCount > 0)
System.out.println(Thread.currentThread().getName() + "卖出一张票" + -- TicketCenter.restCount + "张");
lock.unlock();
}
};
Thread t1 = new Thread(r, "售票员1");
Thread t2 = new Thread(r, "售票员2");
Thread t3 = new Thread(r, "售票员3");
Thread t4 = new Thread(r, "售票员4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
也不说了,OS中那四个必要条件一直重复。
因篇幅问题不能全部显示,请点此查看更多更全内容