线程安全问题和java内存模型

 

  • 什么是线程安全问题
  1. 当多个线程共享同一个全局变量,在做写的操作时,可能会发生线程安全问题。//
    例子: 售卖火车票,多个窗口(多个线程)都在卖火车票数(共享全局变量)。每个窗口在售卖后都会修改票数(写的操作)
    代码:
    /**
     * 窗口售卖火车票
     */
    class Thread03 implements  Runnable{
    
        private int count = 100;
    
        @Override
        public void run() {
            while (count > 0){
                mail();
            }
        }
    
        public synchronized void mail(){
                if (count > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票");
                    count--;
                }
        }
    }
    /**
     * 售卖火车票
     * Create by wangxb
     * 2019-05-14 6:32
     */
    public class Test {
    
        public static void main(String[] args) {
            Thread03 th  = new Thread03();
            Thread t1 = new Thread(th);
            Thread t2 = new Thread(th);
            t1.start();
            t2.start();
        }
    }
  • 什么是多线程的同步
  1. 多个线程共享同一个资源,不会收到其他线程的干扰。
  • 如何解决线程安全问题
  1. 同步代码块:锁是任何obj对象
    /**
     * 窗口售卖火车票
     */
    class Thread03 implements  Runnable{
        private int count = 100;
        private Object obj = new Object();
        @Override
        public void run() {
            while (true){
                mail();
            }
        }
        public void mail(){
            synchronized (obj){
                if (count > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票");
                    count--;
                }
            }
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
            Thread03 th  = new Thread03();
            Thread t1 = new Thread(th);
            Thread t2 = new Thread(th);
            t1.start();
            t2.start();
        }
    }
  2. 静态同步方法:  锁是当前类的字节码文件:Thread03.class
    /**
     * 窗口售卖火车票
     */
    class Thread03 implements  Runnable{
        private static int count = 100;
        private Object obj = new Object();
        @Override
        public void run() {
            while (true){
                mail();
            }
        }
        public static synchronized void mail(){  // 使用当前类的字节码文件: Thread03.class
            if (count > 0) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票");
                count--;
            }
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
            Thread03 th  = new Thread03();
            Thread t1 = new Thread(th);
            Thread t2 = new Thread(th);
            t1.start();
            t2.start();
        }
    }
  3. 同步方法:  锁是this锁
    /**
     * 窗口售卖火车票
     */
    class Thread03 implements  Runnable{
        private int count = 100;
        private Object obj = new Object();
        @Override
        public void run() {
            while (true){
                mail();
            }
        }
        public synchronized void mail(){  // 使用this锁
            if (count > 0) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票");
                count--;
            }
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
            Thread03 th  = new Thread03();
            Thread t1 = new Thread(th);
            Thread t2 = new Thread(th);
            t1.start();
            t2.start();
        }
    }
    
  • 什么是死锁

  1. 概念:同步中嵌套同步,导致无法释放
    例子:
    class Thread01 implements Runnable {
        private int trainCount = 100;
        private Object oj = new Object();
        public boolean flag = true;
    
        public void run() {
    
            if (flag) {
                while (trainCount > 0) {
                    synchronized (oj) {
                        try {
                            Thread.sleep(10);
                        } catch (Exception e) {
                            // TODO: handle exception
                        }
                        sale();
                    }
    
                }
            } else {
                while (trainCount > 0) {
                    sale();
                }
    
            }
    
        }
    
        public synchronized void sale() {
            synchronized (oj) {
                try {
                    Thread.sleep(10);
                } catch (Exception e) {
    
                }
                if (trainCount > 0) {
                    System.out.println(Thread.currentThread().getName() + "," + "出售第" + (100 - trainCount + 1) + "票");
                    trainCount--;
                }
            }
        }
    }
    
    public class Test {
        public static void main(String[] args) throws InterruptedException {
            Thread01 threadTrain = new Thread01();
            Thread t1 = new Thread(threadTrain, "窗口1");
            Thread t2 = new Thread(threadTrain, "窗口2");
            t1.start();
            Thread.sleep(40);
            threadTrain.flag = false;
            t2.start();
    
        }
    }
  • Threadlocal
  1. 什么是Threadlocal
    是为了个每个线程提供一个局部变量,解决线程安全问题。
    class Demo{
    	// 生成序列号共享变量
    	public static Integer count = 0;
    	public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
    		protected Integer initialValue() {
    
    			return 0;
    		};
    
    	};
    
    	public Integer getNum() {
    		int count = threadLocal.get() + 1;
    		threadLocal.set(count);
    		return count;
    	}
    }
    ######################原理##############################
    ThreadLoca实现原理
    ThreadLoca通过map集合
    Map.put(“当前线程”,值);
    
    
    
    
    

     

  • Java内存模型
  1. 什么是java内存模型
    简称(JMM), JMM决定了一个线程对共享变量写入的时候,是否对另一个线程可见
    JMM定义了线程和主内存之间的抽象关系,线程之间的共享变量存储在主内存,每个线程都有一个私有内存,私有内存存的是共享变量的副本
  2. 图例子:

    上图:线程程A与线程B之间如要通信的话,必须要经历下面2个步骤:

    a、首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。

    b、然后,线程B到主内存中去读取线程A之前已更新过的共享变量。

  3. 图例2

    本地内存A和B有主内存中共享变量x的副本。假设初始时,这三个内存中的x值都为0。线程A在执行时,把更新后的x值(假设值为1)临时存放在自己的本地内存A中。当线程A和线程B需要通信时,线程A首先会把自己本地内存中修改后的x值刷新到主内存中,此时主内存中的x值变为了1。随后,线程B到主内存中去读取线程A更新后的x值,此时线程B的本地内存的x值也变为了1。
  • Volatile关键字
  1. 使用volatile关键字,能够解决A线程修改的共享变量(刷新主内存)对另一个线程可见。
  2. volatile可以保证线程的可见性,但不保证原子性
  3. /**
     * 使用volatile修饰变量保证线程可见性
     * Create by wangxb
     * 2019-05-14 20:44
     */
    
    class Thread01 implements  Runnable{
    
        public volatile boolean flag = true;  // volatile可以将子线程修改的共享变量即使刷新主内存
        @Override
        public void run() {
            System.out.println("子线程开始......"+flag);
            while (flag){
            }
            System.out.println("子线程结束....."+flag);
        }
    
        public void setFlag(boolean flag){
            this.flag = flag;
        }
    }
    public class Test {
    
        public static void main(String[] args) throws Exception {
            Thread01 th = new Thread01();
            Thread t1 = new Thread(th);
            t1.start();
            Thread.sleep(3000);
            th.setFlag(false);
            System.out.println("主线程获取flag---"+th.flag);
        }
    }

     

  4. volatile和synchronized的区别
    volatile能保证线程的可见性,不能保证原子性(AtomicInteger保证原子性)
    synchronizedvolatile能保证线程的可见性,也能保证原子性
    volatile的性能优于synchronized
  • AtomicInteger原子类
  1. AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。解决了线程安全问题
  2. 主要应用在计数上
  3. import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * AtomicInteger使用
     * Create by wangxb
     * 2019-05-17 7:41
     */
    class Thread01 implements Runnable{
        public static  AtomicInteger count = new AtomicInteger();
        
        public int set(){
            try {
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 每次加1   == count++
            return count.incrementAndGet();
        }
    
        public void run() {
            while (true){
                System.out.println(Thread.currentThread().getName()+"----"+set());
    
            }
        }
    }
    public class Test {
        
        public static void main(String[] args) {
            Thread01 thread01 = new Thread01();
            Thread th1 = new Thread(thread01);
            Thread th2 = new Thread(thread01);
            th1.start();
            th2.start();
        }
    }
  4. 原子类的实现原理:就是使用了cas无锁机制。我的另一篇文章有介绍
  • automic相关类
  1.  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值