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"+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 欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!) |