多线程线程安全问题

1.什么是线程安全问题?

答:当多个线程共享同一个全局变量,做写的时候,可能会受到其他线程的干扰,导致数据有问题,这种线象叫线程安全问题。
有一种情况可以不用讨论:做读的时候,不会产生线程安全问题
还用多个线程共享一个局部变量时,不会发生线程安全问题

案例:

现在有100张火车票,2个窗口同时抢火车票,用多线程模拟
package com.emple2;

/**
 * @author shkstart
 * @date 2019/6/5- 17:30
 */
class ThreadTrain1 extends Thread{
    //总共有100张票
    private int trainCount  = 100;
    @Override
    public void run(){
        while (trainCount > 0){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //出售火车票
            sale();
        }
    }
    public void sale(){
            System.out.println(Thread.currentThread().getName()+",出售第"+(100-trainCount+1)+"票");
            trainCount--;

    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        ThreadTrain1 threadTrain1 = new ThreadTrain1();
        Thread t1  = new Thread(threadTrain1,"窗口1");
        Thread t2  = new Thread(threadTrain1,"窗口2");
        t1.start();
        t2.start();
    }
}

在这里插入图片描述
出现第101张票的原因:
因为2个线程同时进入sale方法,当第一个线程执行完后trainCount等于0,第二个线程再执行会出现101张票。

解决办法:将trainCount变为局部变量

package com.emple2;

/**
 * @author shkstart
 * @date 2019/6/5- 17:30
 */
class ThreadTrain1 extends Thread{
    //总共有100张票

    @Override
    public void run(){
         int trainCount  = 100;
        while (trainCount > 0){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //出售火车票
            //sale();
            System.out.println(Thread.currentThread().getName()+",出售第"+(100-trainCount+1)+"票");
            trainCount--;

        }
    }
    /*public void sale(){
            System.out.println(Thread.currentThread().getName()+",出售第"+(100-trainCount+1)+"票");
            trainCount--;

    }*/
}
public class ThreadDemo {
    public static void main(String[] args) {
        ThreadTrain1 threadTrain1 = new ThreadTrain1();
        Thread t1  = new Thread(threadTrain1,"窗口1");
        Thread t2  = new Thread(threadTrain1,"窗口2");
        t1.start();
        t2.start();
    }
}

再次执行不会发生线程安全问题

在这里插入图片描述

线程之间的同步:是保证数据的原子性
这个数据不能收到其他线程的干扰
解决办法:

synchronized 
lock  --- jdk1.5并发包 手动锁

2.synchronized的用法

在多线程共享成员变量时加锁
走到 synchronized (oj) 时,看谁先拿到对象锁,没拿到的只能等待别的线程释放对象锁后才能进行,这样做的好处是这块代码永远只能有一个线程操作,保证了线程的原子性。
代码:

package com.emple2;

import sun.awt.Mutex;

/**
 * @author shkstart
 * @date 2019/6/5- 17:30
 */
class ThreadTrain1 extends Thread{
    //总共有100张票
    private  int trainCount  = 100;
    //对象锁
    private Object oj = new Object();
    @Override
    public void run(){

        while (trainCount > 0){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //出售火车票
            sale();

        }
    }
    public void sale(){
        //同步代码块,包裹需要线程安全的问题
        synchronized (oj){
            if(trainCount > 0){
                System.out.println(Thread.currentThread().getName()+",出售第"+(100-trainCount+1)+"票");
                trainCount--;
            }
        }


    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        ThreadTrain1 threadTrain1 = new ThreadTrain1();
        Thread t1  = new Thread(threadTrain1,"窗口1");
        Thread t2  = new Thread(threadTrain1,"窗口2");
        t1.start();
        t2.start();
    }
}

运行效果:
在这里插入图片描述
注意使用到synchronized的时候有2个条件

1.必须有2个以上的线程,需要发生同步
2.多个线程想同步时,必须使同一把锁。
3.保证只有一个线程进行执行

同步的原理:
1.拿到锁,其他线程已经有cpu执行权,一直排队,等待其他线程释放锁。
2.锁在什么时候释放?在代码执行完毕或者是程序抛出异常都会被释放
3.锁已经被释放掉的话,其他线程开始获取锁进去同步中去
4.锁的资源竞争。

缺点:效率低
不释放锁会产生死锁的问题

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值