zoukankan      html  css  js  c++  java
  • 线程安全与死锁

    一、实现多线程的方式:
    方式一:继承Thread类
                  a.自定义类继承Thread类
                  b.在自定义类中重写run()方法
                  c.创建自定义类的对象
                  d.启动线程的对象
    方式二:实现Runnable接口(大多数使用)
                  a.自定义类实现Runnable接口
                  b.在自定义类中重写run()方法
                  c.创建自定义类的对象
                  d.创建Thread类的对象,并把c步骤创建的对象作为构造参数传递
                  优点:避免由于单继承带来的局限性
                            适合多个程序的代码处理同一个资源的情况,把线程同程序的代码、数据有效分离,较好的体现了面向对象的设计思想。

     
    public class SellTicket implements Runnable {
    private int tickets = 100;
    public void run() {
    while(true) {
    if(tickets > 0) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
      }
    }    
    }
    }  
     
     
    public class SellTicketDemo {
    public static void main(String[] args) {
    SellTicket st = new SellTicket();
    Thread t1 = new Thread(st,"窗口1");
    Thread t2 = new Thread(st,"窗口2");
    Thread t3 = new Thread(st,"窗口3");
    t1.start();
    t2.start();
    t3.start();
    }
    }
     

    出现多线程安全问题的原因:
                1.是否是多线程环境
                2.是否共享数据
                3.是否有多条语句操作共享数据
    二、解决线程安全问题——
          方式一、同步代码块
                同步机制:把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行
           格式:synchronized(对象) {需要同步的代码;}
                同步可以解决安全问题的根本原因就在这个对象上。该对象如同锁的功能。多个线程,需要共同拥有一个对象
                用法:
                        在run()方法外创建一个对象 Object obj = new Object(); 对象是任意创建的
                        .......      
                            while(true)  {
                                    synchronized(obj)  {      //相当于一把锁,t1抢到CPU执行权后就锁上了          
                                            if(tickets > 0)  { 
                        .......      //t1睡眠时t2,t3也会抢CPU执行权,但由于锁上进不去。当t1执行完后 t1,t2,t3还会再次抢CPU执行权
              同步的特点:多个线程使用的是同一个锁对象
              同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
            同步方法的格式以及锁对象问题
                  直接将synchronized加到方法上
                    private synchronized void 方法名() {...}  
                    run()方法中直接调用 但是需要注意锁对象的问题 
            同步方法的锁对象是this
            静态方法的锁对象是类的字节码文件对象 即当前类名.class (静态方法是随着类的加载而加载)
            方式二、Lock锁的使用(Lock属于接口)
                    1.明确看到在哪加锁,在哪释放锁
                    2.方法:void lock();获取锁  void unlock();释放锁
                    3.ReentrantLock是Lock的实现类。
                  用法: 
                           在自定义类中定义锁对象 如:private Lock lock = new ReentrantLock();
                      .......      
                            while(true)  {                      
                                    try {                           //加入try是为了防止里面的走错,这样可以直接释放
                                           lock.lock();
                                           if...
                                    }finally {
                                         lock.unlock();
                                    }...
    三、死锁

    死锁是指多个线程运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。

    产生死锁的四个必要条

    1. 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
    2. 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
    3. 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
    4. 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。

    编写产生死锁的代码

     
    public class TestDeadLock {
        private static Object obj1 = new Object();
        private static Object obj2 = new Object();
    
        public static void main(String[] args) {
            new Thread(new Thread1()).start();
            new Thread(new Thread2()).start();
        }
    
        private static class Thread1 implements Runnable {
            @Override
            public void run() {
                synchronized (obj1) {
                    System.out.println("Thread1 拿到了 obj1 的锁!");
                    try {
                    // 停顿2秒的意义在于,让Thread2线程拿到obj2的锁
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj2) {
                        System.out.println("Thread1 拿到了 obj2 的锁!");
                    }
                }
            }
        }
    
        private static class Thread2 implements Runnable {
            @Override
            public void run() {
                synchronized (obj2) {
                    System.out.println("Thread2 拿到了 obj2 的锁!");
                    try {
                    // 停顿2秒的意义在于,让Thread1线程拿到obj1的锁
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj1) {
                        System.out.println("Thread2 拿到了 obj1 的锁!");
                    }
                }
            }
        }
    
    }
  • 相关阅读:
    实验二
    实验一简单的加减乘除
    自我简介
    软件工程——第五次博客作业
    《软件测试》--第四次博客作业
    软件测试 第三次作业
    软件测试 第二次作业
    个人简介
    软件测试 第一次测评
    AE CC 装不上,安装程序检测到计算机重新启动的过程可能暂停。建议退出安装程序,重新启动计算机,然后再重试。
  • 原文地址:https://www.cnblogs.com/danxun/p/12519244.html
Copyright © 2011-2022 走看看