关于多线程的一些知识点(二)——临界资源

2019-10-20  本文已影响0人  li_荔枝

临界资源问题

先看例子

public class SourceConflict {

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (TicketCenter.currnetTicket > 0) {
                    System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+ --TicketCenter.currnetTicket);
                }
            }
        };
        
        Thread t1 = new Thread(runnable, "t1");
        Thread t2 = new Thread(runnable, "t2");
        Thread t3 = new Thread(runnable, "t3");
        Thread t4 = new Thread(runnable, "t4");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
    
    
}

class TicketCenter{
    public static int currnetTicket = 100;
}

运行程序,四个线程共享ticket资源,会同时操作票资源,不做处理会出现下面的问题


image.png

解决方法一:同步代码段

public class SynchronizedDemo {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (TicketCenter.currnetTicket > 0) {
                    //对象锁
                    synchronized ("") {
                        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+ --TicketCenter.currnetTicket);
                    }
                }
            }
        };
        
        Thread t1 = new Thread(runnable, "t1");
        Thread t2 = new Thread(runnable, "t2");
        Thread t3 = new Thread(runnable, "t3");
        Thread t4 = new Thread(runnable, "t4");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

上面的 //对象锁 synchronized ("") 可替换成
//类锁 synchronized(SynchronizedDemo.class)
只要保证四个线程看到的是同一所即可,
synchronized(new SynchronizedDemo())会报错,因为每次都会生成不同对象

好接下来我们看运行代码结果(我们的结果不一定相同)


image.png

但是!!!!!!!!


image.png

这是因为t2卖票时,t1,t3,t4拿到资源在锁外等待,线程切换的时候,他们看到的票数还是>0的,当t2卖出最后一张,票数为0,t1,t3,t4再做卖票动作时,会产生负数。

修改成这样就好了

synchronized ("") {
                        if (TicketCenter.currnetTicket == 0) {
                            return;
                        }
                        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+ --TicketCenter.currnetTicket);
                    }

解决方法二:同步方法

public class SynchronizedFunction {

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (TicketCenter.currnetTicket > 0) {
                    sell();
                }
            }
        };
        
        Thread t1 = new Thread(runnable, "t1");
        Thread t2 = new Thread(runnable, "t2");
        Thread t3 = new Thread(runnable, "t3");
        Thread t4 = new Thread(runnable, "t4");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
    
    /*同步方法
    静态方法:同步锁就是类锁, 当前类.class
    非静态方法: 同步锁是 this*/
    public synchronized static void sell(){
        if (TicketCenter.currnetTicket == 0) {
            return;
        }
        System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+ --TicketCenter.currnetTicket);
    }
}

看结果


image.png

当需要同步的逻辑比较复杂的时候可以将他们放在方法里

解决方法三:显示锁

public class LockDemo {
public static void main(String[] args) {

    final ReentrantLock lock = new ReentrantLock();
    
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (TicketCenter.currnetTicket > 0) {
                //对临界资源加上显示锁
                lock.lock();
                if (TicketCenter.currnetTicket <= 0) {
                    return;
                }
                
                System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+ --TicketCenter.currnetTicket);
                //对临界资源释放锁
                lock.unlock();
            }
        }
    };
    
    Thread t1 = new Thread(runnable, "t1");
    Thread t2 = new Thread(runnable, "t2");
    Thread t3 = new Thread(runnable, "t3");
    Thread t4 = new Thread(runnable, "t4");
    
    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

}
结果没有问题,但是。。。
运行之后程序没有停止,有大佬可以告诉我为什么吗?

上一篇 下一篇

猜你喜欢

热点阅读