zoukankan      html  css  js  c++  java
  • java基础25 线程的常用方法、线程安全问题、死锁现象

    一、线程的常用方法

    1、Thread(String name):初始化线程的名字
    2、 setName(String name):设置线程的名字
    3、 getName():返回线程的名字
    4、 sleep(long millis):线程睡眠指定毫秒数.静态的方法.
    5、 currentThread(): 返回当前线程对象
    6、 getPriority():返回当前线程对象的优先级  默认优先级5
    7、 setPriority(int newPriority):设置线程优先级   虽然设置了优先级,但是具体的实现取决于底层操作系统实现(最大优先级数是10,最小的是1,默认的是5)

    8、其他几个方法,1.8、线程生命周期处 ..............

    1.1、例1   Thread()、currentThread()

     1 package com.zn.thread;
     2 
     3 /**
     4  * @author DSHORE / 2018-5-7
     5  *
     6  */
     7 public class Demo2 extends Thread {
     8 
     9     public Demo2(String name) {
    10         super(name);
    11     }
    12     @Override
    13     public void run() {
    14         //Thread.currentThread():返回当前线程对象
    15         System.out.println("当前线程:"+Thread.currentThread());//运行结果:当前线程:Thread[二狗子线程,5,main];说明:当前线程是二狗子线程,优先级是5
    16         System.out.println("this:"+this);//运行结果:this:Thread[二狗子线程,5,main]
    17         
    18         for(int i=0;i<100;i++){
    19             System.out.println(Thread.currentThread().getName()+i);
    20         }
    21     }
    22     public static void main(String[] args) {
    23         Demo2 d = new Demo2("二狗子线程");
    24         d.start();
    25         
    26         System.out.println("当前线程:"+Thread.currentThread());//运行结果:当前线程:Thread[main,5,main] 说明:当前线程是主线程(main线程),优先级也是5
    27         
    28         for(int j=0;j<100;j++){
    29             System.out.println("主线程:"+j);
    30         }
    31     }
    32 }

    结果图

                       

    1.2、例2    setName()、getName()

        1、setName():设置线程的名字
        2、getName():获取线程的名字

     1 package com.zn.thread;
     2 
     3 /**
     4  * @author DSHORE / 2018-5-7
     5  *
     6  */
     7 public class Demo2 extends Thread {
     8 
     9     public Demo2(String name) {
    10         super(name);
    11     }
    12     @Override
    13     public void run() {//run()方法中的代码,都是自定义线程
    14         for(int i=0;i<100;i++){
    15             System.out.println(Thread.currentThread().getName()+i);//获取当前线程的名字
    16         }
    17     }
    18     public static void main(String[] args) {
    19         //创建一个线程对象
    20         Demo2 d = new Demo2("二狗子线程");
    21         d.setName("狗剩线程");//设置线程的名字
    22         d.start();
    23         
    24         Thread.currentThread().setName("隔壁老王线程");
    25         for(int j=0;j<100;j++){
    26             System.out.println(Thread.currentThread().getName()+j);
    27         }
    28     }
    29 }

    结果图      (狗剩线程 覆盖掉了 二狗子线程)

     

    1.3、例3     sleep()

    sleep():指定线程睡眠的时间(毫秒为单位)

     1 package com.zn.thread;
     2 
     3 /**
     4  * @author DSHORE / 2018-5-7
     5  *
     6  */
     7 public class Demo2 extends Thread {
     8 
     9     public Demo2(String name) {
    10         super(name);
    11     }
    12     @Override
    13     public void run() {
    14         for(int i=0;i<100;i++){
    15             System.out.println(Thread.currentThread().getName()+i);
    16             try {
    17                 Thread.sleep(100);//休眠(暂停)100毫秒       1秒 = 1000毫秒
    18             } catch (InterruptedException e) {//Thread类的run方法没有抛出异常类型,所以子类不能抛出异常
    19                 e.printStackTrace();//打印异常信息
    20             }
    21         }
    22     }
    23     public static void main(String[] args) {
    24         //创建一个线程对象
    25         Demo2 d = new Demo2("二狗子线程");
    26         d.start();
    27         
    28         Thread.currentThread().setName("隔壁老王线程");
    29         for(int j=0;j<100;j++){
    30             System.out.println(Thread.currentThread().getName()+j);
    31         }
    32     }
    33 }

    运行结果图  (其中一次的运行结果)

     使用sleep()方法,睡了一下,几乎都被“隔壁老王全抢了线程”;二狗子线程在后面才执行

    1.4、例4      getPriority()

    getPriority():获取当前线程对象的优先级    默认优先级:5
    setPriority():设置优先级数

     1 package com.zn.thread;
     2 
     3 /**
     4  * @author DSHORE / 2018-5-7
     5  *
     6  */
     7 
     8 public class Demo3 extends Thread {
     9      @Override
    10      public void run() {
    11          Thread t = new Thread();//先创建线程对象,再去获取优先级数或设置优先级数
    12          t.setPriority(10);//直接设置优先级
    13          for(int i=0;i<100;i++){
    14              System.out.println("当前线程:"+i+"	"+t.getPriority());//getPriority():获取该线程对象的优先级数;   默认优先级是5
    15          }
    16      }
    17      public static void main(String[] args) {
    18          //创建一个线程对象
    19          Demo3 d = new Demo3();
    20          d.start();
    21  
    22          Thread.currentThread().setName("隔壁老王线程");
    23          for(int j=0;j<100;j++){
    24              System.out.println(Thread.currentThread().getName()+j);
    25          }
    26      }
    27 }

    结果图

                        

     

    二、线程安全问题

    2.1、java线程同步机制

        方式一:同步代码块
             synchronized(锁对象){
                   需要被同步的代码...
             }

        方式二:同步函数

            修饰符 synchronized 返回值类型 函数名(参数类型  参数名){

            }

    public synchronized void add(int a) { //即:在普通函数上面加个 synchronized 
    
    }

    2.2、同步代码块要注意的问题

        1.任意的一个对象都可以作为锁对象
        2.在同步代码块中调用了sleep并不是释放锁对象.
        3.只有真正存在线程安全问题是,才使用同步代码块,否则会降低效率
        4.多线程操作的锁对象必须是唯一共享的,否则就无效了

    实例1 (出现线程安全问题)

    package com.zn.thread;
    
    /**
     * @author DSHORE / 2018-5-8
     *
     * 模拟3个窗口同时在售20张票
     */
    
    class Windows extends Thread{
        static int num=20;//票数  问题1 //得使用static共享num给三个线程(w1、w2、w3)一起使用     注:这是第二张结果图的程序,第一张int num 前面是没有static的。
        public Windows(String name){
            super(name);
        }
        @Override
        public void run() {
            while(true){//问题2  此处应该加个同步锁
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+"售出第"+num+"");
                    num--;
                }else{
                  System.out.println("票已售罄");
                  break;
                }
            }
        }
    }
    public class Demo3 {
        public static void main(String[] args) {
            //创建3个线程对象,模拟3个窗口
            Windows w1=new Windows("窗口1");
            Windows w2=new Windows("窗口2");
            Windows w3=new Windows("窗口3");
            //开启线程售票
            w1.start();
            w2.start();
            w3.start();
        }
    }

    运行结果图

                                        

    两张图都出现了“三个窗口都有售出同一张票的情况”;即:出现了线程安全问题,解决该问题看例2

    问题1:为什么出现了:售出60张票?
        答:把num这个数据共享给三个线程对象使用,使用static
    问题2出现线程安全问题
        线程安全问题的解决方案:sun提供了同步机制让我们解决这类问题

    实例2 (完美实例)

     1 package com.zn.thread;
     2 
     3 /**
     4  * @author DSHORE / 2018-5-8
     5  *
     6  * 模拟3个窗口同时在售20张票
     7  */
     8 //同步代码块    例子
     9 class Windows extends Thread{
    10     static int num = 20;//票数    
    11 //static Object o=new Object(); //多线程操作的锁对象必须是唯一共享 12 public Windows(String name){ 13 super(name); 14 } 15 @Override 16 public void run() { 17 while(true){ 18 //同步代码块 19 synchronized ("") { //synchronized (o){ } //任意的一个对象都可以作为锁对象 20 if(num>0){ 21 System.out.println(Thread.currentThread().getName()+"售出第"+num+""); 22 try { 23 Thread.sleep(100);//睡眠100毫秒 24 } catch (InterruptedException e) { 25 e.printStackTrace();//打印异常信息 26 } 27 num--; 28 }else{ 29 System.out.println("票已售罄"); 30 break; 31 } 32 } 33 } 34 } 35 } 36 public class Demo3 { 37 public static void main(String[] args) { 38 //创建3个线程对象,模拟3个窗口 39 Windows w1=new Windows("窗口1"); 40 Windows w2=new Windows("窗口2"); 41 Windows w3=new Windows("窗口3"); 42 //开启线程售票 43 w1.start(); 44 w2.start(); 45 w3.start(); 46 } 47 }

    运行结果图

    2.3、出现安全问题的根本原因

        1.存在两个或者两个以上的线程对象,而且线程之间共享一个资源.
        2.有多个语句操作了共享资源

    2.4、同步函数要注意的问题

        1.如果是一个非静态的同步函数,锁对象是this对象(相当于全局变量)。如果是静态的同步函数的锁,对象是当前函数锁属的类的字节码文件(class对象)。
        2.同步函数锁对象是固定的,不能由你来指定

    推荐使用同步代码块
        原因:
           1.同步代码块锁对象由我们随意指定,方便控制;同步函数锁对象是固定的,不能由我们指定
           2.同步代码块可以很方便的控制需要同步的范围,同步函数必须是整个函数的所有代码都被同步了.

    //需求:两人同时取钱(卡+本子)
    
     //同步函数  例子       
    class BankThread extends Thread{
        static int count=50000;
        public BankThread(String name) {
            super(name);
        }
        @Override
        public  void run() {
                getMoney();
        }
      //同步函数
    public static synchronized void getMoney(){ //静态的函数---->函数所属的类的字节码文件对象 BanckThread.class唯一的 while(true){ if(count>0){ System.out.println(Thread.currentThread().getName()+"取走了10000,还剩"+(count-10000)+""); count=count-10000; }else{ System.out.println("取完了..滚蛋"); break; } } } } public class Demo1 { public static void main(String[] args) { BankThread b=new BankThread("狗蛋"); BankThread b1=new BankThread("铁蛋"); b.start(); b1.start(); } } //问题:结果只有一个人能取到钱,另一个人始终没办法取到钱。原因:同步函数把所有代码都锁住了;这里应该用同步代码块

    三、死锁现象

       java同步机制解决了线程安全问题,但是也同时引发了死锁现象

    3.1、死锁现象出现的根本原因

        1.存在两个或者两个以上的线程.
        2.存在两个或者两个以上共享资源.

    3.2、死锁问题的解决方案

       没有方案,只能尽量避免发生而已.

     3.3、实例

     1 package com.zn.thread;
     2 
     3 /**
     4  * @author DSHORE / 2018-5-11
     5  *
     6  * java同步机制解决了线程安全问题,但是也同时引发了了死锁现象
     7  * 
     8  * 需求:两个人抢着去打开电视机,但遥控器和电池是分开的,只有一个人同时拿到遥控器和电池才能打开电视机
     9  */
    10 class DeadLock extends Thread{
    11     public DeadLock(String name) {
    12         super(name);
    13     }
    14     @Override
    15     public void run() {
    16         if("张三".equals(Thread.currentThread().getName())){
    17             synchronized ("电池") {
    18                 System.out.println("张三拿到了电池,准备去拿遥控器");
    19                 synchronized ("遥控器") {
    20                     System.out.println("张三拿到了电池和遥控器,正在打开电视机 看电视");
    21                 }
    22             }
    23         }else if("李四".equals(Thread.currentThread().getName())){
    24             synchronized ("遥控器") {
    25                 System.out.println("李四拿到了遥控器,准备去拿电池");
    26                 synchronized ("电池") {
    27                     System.out.println("李四拿到了遥控器和电池,正在打开电视机中");
    28                 }
    29             }
    30         }
    31     }
    32 }
    33 public class Demo4 {
    34     public static void main(String[] args) {
    35         //创建线程对象
    36         DeadLock d = new DeadLock("张三");
    37         DeadLock d1 = new DeadLock("李四");
    38         //开启线程
    39         d.start();
    40         d1.start();
    41     }
    42 }

    运行结果图

         

    原创作者:DSHORE

    作者主页:http://www.cnblogs.com/dshore123/

    原文出自:http://www.cnblogs.com/dshore123/p/9004156.html

    欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!

  • 相关阅读:
    Django缓存大总结
    Django之视图 ListView
    Django中间件之加载分析
    Django启动过程之超级详细分析
    Django中间件
    RabbitMq与Celery应用示意图
    爬虫的基本原理
    RestFramework的过滤组件 和 分页组件
    python注释、输入格式化输出输出及数据类型
    编程语言的发展历史及python的初了解
  • 原文地址:https://www.cnblogs.com/dshore123/p/9004156.html
Copyright © 2011-2022 走看看