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.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"+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(锁对象){
               需要被同步的代码...
         }

    方式二:同步函数

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

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

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

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

2.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 }

运行结果图

原创作者:DSHORE

出自:http://www.cnblogs.com/dshore123/

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

猜你喜欢

转载自www.cnblogs.com/dshore123/p/9004156.html