(前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频 百度网盘链接地址:http://pan.baidu.com/s/1sjQRHDz)
目录:一、线程的两种创建方式 二、线程的五种状态、线程操作中常用的方法 三、多线程安全 四、使用同步的弊端 五、单例设计模式中的多线程(面试重点)
一、线程的两种创建方式
1、实现Runnable接口(主流)
代码示例:
1 public class ThreadTest{ 2 3 public static void main(String[] args) throws InterruptedException{ 4 ThreadImple ti=new ThreadImple(); 5 Thread thread=new Thread(ti); 6 7 thread.start(); 8 } 9 } 10 class ThreadImple implements Runnable { 11 12 @Override 13 public void run() { 14 for(int i=0;i<60;i++) 15 System.out.println("thread implements runnable..."+i); 16 } 17 }
2、继承Thread类
1 public class ThreadTest{ 2 3 public static void main(String[] args) throws InterruptedException{ 4 ThreadExtends ti=new ThreadExtends(); 5 6 ti.start(); 7 } 8 } 9 class ThreadExtends extends Thread { 10 11 public void run() { 12 for(int i=0;i<60;i++) 13 System.out.println("extend thread class..."+i); 14 } 15 }
3、两种创建方式的区别
实现方式的运行代码存放在接口子类的run方法中;实现方式避免了单继承的局限性,建议使用
继承方式的运行代码存放在Thread子类的run方法中
二、线程的五种状态 线程操作中常用的方法
三、多线程安全
问题:一个线程操作多条语句来共享数据时,一个线程对多条语句只执行了一部分,另一个线程便参与进来执行了,导致共享数据出错。
如何寻找问题: 1、明确哪些代码示多线程运行代码 2、明确共享数据 3、明确多线程运行代码中哪些语句是操作共享数据的。
解决办法:同步代码块:
Synchronized( 锁 ){
需要被同步的代码;
}
同步函数:在函数前加synchronized修饰符。
使用同步要满足三个前提:1、必须有两个或两个以上线程 2、必须是多个线程使用同一个锁
弊端:每次执行时都要判断锁,浪费资源。
普通同步函数的锁是this ,静态函数的锁是其所在文件字节码对象(.class)
简单模拟售票代码:
1 /* 2 程序一共创建三个线程模拟三个售票窗口 ticket=100将票号设为1-100 我们希望票号不重复 3 遗憾的是结果会出现票号为负数、相同票号的问题 也就是我们要讲到的线程不安全问题 4 */ 5 public class SaleTicketUnsafe { 6 7 public static void main(String[] args) { 8 9 Ticket ticket=new Ticket(); 10 11 new Thread(ticket).start(); 12 new Thread(ticket).start(); 13 new Thread(ticket).start(); 14 15 } 16 17 } 18 class Ticket implements Runnable{ 19 20 private int ticket=100; 21 public void run(){ 22 while(true){ 23 if(ticket>0){ 24 try { 25 Thread.sleep(10);//线程出错概率不是很大,所以要让线程休眠sleep()来将问题暴露出来 26 } catch (InterruptedException e) { 27 // TODO Auto-generated catch block 28 e.printStackTrace(); 29 } 30 System.out.println(Thread.currentThread().getName()+"售票口出售---车票号:"+ticket--); 31 } 32 } 33 34 } 35 }
使用同步代码块的方式改进后的程序
1 /*同步代码块的方式解决了问题*/ 2 public class SaleTicketSafe { 3 4 public static void main(String[] args) { 5 Tickets ticket=new Tickets(); 6 7 new Thread(ticket).start(); 8 new Thread(ticket).start(); 9 new Thread(ticket).start(); 10 } 11 12 } 13 class Tickets implements Runnable{ 14 15 private int ticket=100; 16 Object obj=new Object(); 17 @Override 18 public void run() { 19 while(true){ 20 synchronized(obj){//同步代码块 21 if(ticket>0){ 22 try { 23 Thread.sleep(10); 24 } catch (InterruptedException e) { 25 // TODO Auto-generated catch block 26 e.printStackTrace(); 27 } 28 System.out.println(Thread.currentThread().getName()+"售票口出售---车票号:"+ticket--); 29 } 30 } 31 } 32 } 33 34 }
四、使用同步会出现死锁情况(面试时会要求写一个死锁程序)
问题:多线程各自持有不同的锁没释放,而又彼此需要对方的锁。
原因:同步中嵌套同步,而它们的锁却不同
一个简单的死锁程序:
1 public class DieLock { 2 3 public static void main(String[] args){ 4 //开启两个线程测试 5 Thread t1=new Thread(new Test(true)); 6 t1.start(); 7 Thread t2=new Thread(new Test(false)); 8 t2.start(); 9 } 10 } 11 class Test implements Runnable{ 12 boolean flag; 13 public Test(boolean f){ 14 this.flag=f; 15 } 16 @Override 17 public void run() { 18 if(flag){ 19 while(true){ 20 synchronized(Lock.lockb){ 21 System.out.println("if locka"); 22 synchronized(Lock.locka){ 23 System.out.println("if lockb"); 24 } 25 } 26 } 27 }else{ 28 while(true){ 29 synchronized(Lock.locka){ 30 System.out.println("else locka"); 31 synchronized(Lock.lockb){ 32 System.out.println("else lockb"); 33 } 34 } 35 } 36 } 37 } 38 //单独定义两个不同的锁 39 static class Lock{ 40 static Object locka=new Object(); 41 static Object lockb=new Object(); 42 } 43 }
五、单例设计模式中的多线程(面试重点)
饿汉式、懒汉式(是线程不安全的,需要同步)
将懒汉式同步有两种方式:
1、下面代码中在getInstance方法前用synchronized修饰,通过同步函数来解决,每次都要同步比较消耗资源
2、就是注释中用同步块的方式,用双重判断(s==null)只需同步一次,避免多消耗资源,推荐使用
1 public class Single{ 2 public static void main(String[] args){ 3 4 Singlel s=Singlel.getInstance(); 5 6 } 7 } 8 //懒汉式 9 class Singlel extends Single{ 10 11 private Singlel(){} 12 private static Singlel s=null; 13 14 public static synchronized Singlel getInstance(){ 15 if(s==null) 16 s=new Singlel(); 17 // if(s==null){ 18 // synchronized(Singlel.class){ 方法二、双重判断 ,提高效率 19 // if(s==null) 20 // s=new Singlel(); 21 // } 22 // } 23 return s; 24 } 25 } 26 //饿汉式 27 class Singlee extends Single{ 28 private Singlee(){} 29 private static Singlee s=new Singlee(); 30 31 public static Singlee getInstance(){ 32 return s; 33 } 34 35 }
初学者难免错误,欢迎评判指教,持续更正ing...........