• 线程安全


    1. 什么叫线程安全?

        多线程对共享资源进行的操作,受到其他线程的干扰,导致数据偶问题,这种现象叫做线程安全问题。

    package com.cn.test.thread;
    
    public class TrainThread implements Runnable {
    
        /**
         * 两个线程进行售票100张
         */
        private  int trainTicket = 100;
        @Override
        public void run() {
            
            while (trainTicket > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 进行售票
                System.out.println(Thread.currentThread().getName() + "开始售票:" + (100 - trainTicket + 1) + "张");
                trainTicket--;
            }
        }
    
        public static void main(String[] args) {
            TrainThread train = new TrainThread();
            Thread  t1 = new Thread(train,"窗口1");
            Thread  t2 = new Thread(train,"窗口2");
            t1.start();
            t2.start();
        }
    }

    运行结果:

    窗口1开始售票:1张
    窗口2开始售票:1张
    窗口1开始售票:3张
    窗口2开始售票:3张
    窗口1开始售票:5张
    窗口2开始售票:5张
    窗口1开始售票:7张
    窗口2开始售票:7张
    窗口2开始售票:9张
    窗口1开始售票:9张
    窗口2开始售票:11张
    窗口1开始售票:12张
    窗口2开始售票:13张
    窗口1开始售票:14张
    窗口2开始售票:15张
    窗口1开始售票:16张
    窗口2开始售票:17张
    窗口1开始售票:18张
    窗口2开始售票:19张
    窗口1开始售票:20张
    窗口2开始售票:21张
    窗口1开始售票:22张
    窗口2开始售票:23张
    窗口1开始售票:24张
    窗口2开始售票:25张
    窗口1开始售票:26张
    窗口2开始售票:27张
    窗口1开始售票:28张
    窗口2开始售票:29张
    窗口1开始售票:30张
    窗口2开始售票:31张
    窗口1开始售票:32张
    窗口2开始售票:33张
    窗口1开始售票:34张
    窗口2开始售票:35张
    窗口1开始售票:36张
    窗口2开始售票:37张
    窗口1开始售票:38张
    窗口2开始售票:39张
    窗口1开始售票:40张
    窗口2开始售票:41张
    窗口1开始售票:42张
    窗口2开始售票:43张
    窗口1开始售票:44张
    窗口2开始售票:45张
    窗口1开始售票:46张
    窗口2开始售票:47张
    窗口1开始售票:48张
    窗口2开始售票:49张
    窗口1开始售票:50张
    窗口2开始售票:51张
    窗口1开始售票:52张
    窗口2开始售票:53张
    窗口1开始售票:54张
    窗口2开始售票:55张
    窗口1开始售票:56张
    窗口2开始售票:57张
    窗口1开始售票:58张
    窗口2开始售票:59张
    窗口1开始售票:60张
    窗口2开始售票:61张
    窗口1开始售票:62张
    窗口2开始售票:63张
    窗口1开始售票:64张
    窗口2开始售票:65张
    窗口1开始售票:66张
    窗口2开始售票:67张
    窗口1开始售票:68张
    窗口2开始售票:69张
    窗口1开始售票:70张
    窗口2开始售票:71张
    窗口1开始售票:72张
    窗口2开始售票:73张
    窗口1开始售票:74张
    窗口2开始售票:75张
    窗口1开始售票:76张
    窗口2开始售票:77张
    窗口1开始售票:78张
    窗口2开始售票:79张
    窗口1开始售票:80张
    窗口2开始售票:81张
    窗口1开始售票:82张
    窗口2开始售票:83张
    窗口1开始售票:84张
    窗口2开始售票:85张
    窗口1开始售票:86张
    窗口2开始售票:87张
    窗口1开始售票:88张
    窗口2开始售票:89张
    窗口1开始售票:90张
    窗口2开始售票:91张
    窗口1开始售票:92张
    窗口2开始售票:93张
    窗口1开始售票:94张
    窗口2开始售票:95张
    窗口1开始售票:96张
    窗口2开始售票:97张
    窗口1开始售票:98张
    窗口2开始售票:99张
    窗口1开始售票:100张
    窗口2开始售票:101张

    线程安全解决的办法:

            使用多线程之间同步synchronized或使用锁(lock)。

    为什么使用线程同步或使用锁能解决线程安全问题呢?

           将可能发生线程安全的代码,在同一时刻只有一个线程对此进行操作,代码执行完毕之后释放锁之后才让其他线程并发执行,这样就会解决线程安全的问题。

    什么是线程同步?

         多个线程共享同一个资源,不会受到其他线程的干扰。

    解决办法1:

           同步代码块。 将可能发生线程安全的代码用同步代码块包裹起来。

                  synchronized(同一个数据) {

                       可能会发生线程冲突问题

                    }

            同步代码块需要传递的对象(锁对象):就是锁住这个对象,表示这个对象正在为我服务,其他人不能用(非synchronized代码块、方法除外)。

    		
    		while (trainTicket > 0) {
    			try {
    				Thread.sleep(50);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			synchronized (obj) {
    				// 进行售票
    				if (trainTicket > 0) {
    					System.out.println(Thread.currentThread().getName() + "开始售票:" + (100 - trainTicket + 1) + "张");
    					trainTicket--;
    				}
    			}
    		}
    	
    

      解决办法2:

               同步函数,在发生线程安全的函数中加入sychnorized关键字。

      静态同步函数:

         方法上加上static关键字,使用synchronized 关键字修饰 或者使用类.class文件。静态的同步函数使用的锁是  该函数所属字节码文件对象可以用 getClass方法获取,也可以用当前  类名.class 表示。

    死锁:

    同步中嵌套同步,导致锁无法释放

    package com.cn.test.thread;
    
    public class TestDeadThread implements Runnable {
    
        
        
        private boolean flag = true;
        private static int trainCount = 100;
        private Object mutex = new Object();
    
        @Override
        public void run() {
            if (flag) {
                while(true) {
                    synchronized (mutex) {
                         sale();
                    }
                }
            } else {
                while (true) {
                    sale();
                }
    
            }
    
        }
    
        private synchronized void sale() {
            synchronized (mutex) {
                if (trainCount > 0) {
                    try {
                        Thread.sleep(40);
                    } catch (Exception e) {
    
                    }
                    System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "张票.");
                    trainCount--;
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            TestDeadThread  test1 = new TestDeadThread();
            Thread t1 = new Thread(test1,"thread-1");
            Thread t2 = new Thread(test1,"thread-2");
            t1.start();
            Thread.sleep(40);
            test1.flag  = false;
            t2.start();
    
    
        }
    
    }

    运行结果:

    thread-1,出售 第1张票.
    thread-1,出售 第2张票.
    thread-1,出售 第3张票.
    thread-1,出售 第4张票.
    thread-1,出售 第5张票.
    thread-1,出售 第6张票.
    thread-1,出售 第7张票.
    thread-1,出售 第8张票.
    thread-1,出售 第9张票.
    thread-1,出售 第10张票.
    thread-1,出售 第11张票.
    thread-1,出售 第12张票.
    thread-1,出售 第13张票.
    thread-1,出售 第14张票.
    thread-1,出售 第15张票.
    thread-1,出售 第16张票.
    thread-1,出售 第17张票.
    thread-1,出售 第18张票.
    thread-1,出售 第19张票.
    thread-1,出售 第20张票.
    thread-1,出售 第21张票.
    thread-1,出售 第22张票.
    thread-1,出售 第23张票.
    thread-1,出售 第24张票.
    thread-1,出售 第25张票.
  • 相关阅读:
    ConcurrentHashMap之实现细节
    Java 开发 2.0: 用 Hadoop MapReduce 进行大数据分析
    mapreduce从wordcount开始
    centos 5.5 安装mysql 5.5 全程详细记录 RPM方式安装
    使用GDAL工具对OrbView3数据进行正射校正
    centos 5.5 mysql5.5 乱码
    netty vs mina netty和mina的区别
    VC欣赏、家人是阻力,极客化、国际化——90后创业生态
    悲惨而又丢人的创业经历:草根创业者含恨倾诉为什么失败
    悲惨而又丢人的创业经历:草根创业者含恨倾诉为什么失败
  • 原文地址:https://www.cnblogs.com/startSeven/p/10217262.html
Copyright © 2020-2023  润新知