您的位置:首页 > 编程语言 > Java开发

java基础25 线程的常用方法、线程安全问题、死锁现象

2018-05-07 18:05 686 查看

一、线程的常用方法

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"+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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐