黑马程序员——线程小结

来源:互联网 发布:同盾大数据 编辑:程序博客网 时间:2024/06/05 18:22

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一,创建线程的两种方式:

创建线程的第一种方式:继承Thread类

步骤:
1.定义类继承Thread
2.复写Thread类中的run()方法:将自定义的代码存储在run里让线程执行。

3.调用线程的start()方法,该方法有两个作用,启动线程,调用run方法。必须要调用,否则创建了线程但没有运行。


为什么要覆盖run方法呢?
Thread类用于描述线程,该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
线程都有自己的默认名称,都是从0开始编号。


创建线程的第二种方法:声明实现Runnable接口的类,然后该类覆盖run方法。
步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法::将线程要运行的代码存放在该方法中。
3.通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thead类的构造函数。
5.调用Thread类的start方法,启动线程,并调用Runnable接口子类中的run方法

二:实现方式和继承方式的区别(非常重要) :
实现方式避免了多继承的局限性。Java是单继承的,继承了Thread类就无法继承其他类。
建议使用实现方式。(资源可以独立)


线程代码存放位置不同:继承方式存放在Thread子类run方法中,实现方式存放在接口子类run方法中。


三:安全问题:

在售票的例子中,出现0,-1,-2等错票。

原因:当多条语句操作一个共享数据时,一个线程对多条语句只执行了其中一部分,还没执行完另一个线程参与进来执行,导致共享数据出错。

解决办法,让一个线程执行完,过程中,其他线程不可参与。
Java为了解决安全问题提供了专业的解决方式:同步代码块。
synchronized(对象){
需要被同步的代码块。
对象如同锁,持有锁的线程可以在同步中执行,就如同火车上的卫生间。

必须保证同步中只有一个线程在执行,但是,只将操作共享数据的代码放进同步、

}
如何找问题:
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据的。




四:死锁:同步中嵌套同步,并且锁不同。


例子:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /*需求;死锁程序 
  2. 线程1持有locka锁,进入同步代码块儿后继续执行代码想要持lockb锁, 
  3. 同时线程2持有lockb锁,继续执行代码想要获取locka锁, 
  4. 但是,两个线程都想获取对方持有的锁,但都不放手自己的锁,因此导致死锁。 
  5. */  
  6. class Test implements Runnable{     
  7.     private  boolean flag;  
  8.     Test(boolean flag){  
  9.         this.flag = flag;  
  10.           
  11.     }  
  12.     public void run(){  
  13.         if(flag){  
  14.                 synchronized(Lock.locka){  
  15.                     System.out.println("locka...");  
  16.                     synchronized(Lock.lockb){  
  17.                         System.out.println("lockb...");  
  18.                     }  
  19.                 }  
  20.         }  
  21.         else{  
  22.             synchronized(Lock.lockb){  
  23.                     System.out.println("lockb...");  
  24.                     synchronized(Lock.locka){  
  25.                         System.out.println("locka...");  
  26.                     }  
  27.                 }  
  28.         }  
  29.     }  
  30. }  
  31. class Lock{  
  32.     static Object  locka = new Object();  
  33.     static Object  lockb = new Object();  
  34. }  
  35. class DeadLock{  
  36.     public static void main(String[] args){  
  37.         Thread t1 = new Thread(new Test(true));  
  38.         Thread t2 = new Thread(new Test(false));  
  39.         t1.start();  
  40.         t2.start();  
  41.     }  
  42. }  


五:线程间通信: 其实就是多个线程操作同一个资源,但是动作不同。


等待唤醒机制:
线程池:处于wait()状态的线程都在线程池中等待,按顺序存入,被叫醒时通常是第一个被叫醒。
wait():等待,
notify()/notifyAll()  :唤醒等待的线程。
注意:wait(),notify()等方法被定义在Object中,必须用在同步中,同时,必须指持有锁的线程。因为要对持有监视器(锁)的线程操作。   x.wait();
只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒。即等待和唤醒必须是同一把锁,但是,锁可以是任意对象,所以,可以被任意对象调用的方法定义在Object中。


JDK1.5版本中提供了多线程升级解决方案,将同步synchronized替换成显式的Lock操作。
将Object中的wait,notify,notifyAll,替换为Condition对象,该对象可以通过lock锁获取。
实现了本方只唤醒对方的操作。


六:如何停止线程:只有一种方法,就是run方法结束,开启多线程,运行代码多数是循环结构,只要控制住循环,就可以让run方法结束,线程就结束了。
特殊情况:当线程处于冻结状态,就无法读取结束标记,线程不会结束,当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结状态
进行清除,强制让线程恢复到运行状态中,这样就可以操作标记,让线程结束。
Thread类中提供了该方法:interrupt();
0 0
原创粉丝点击