黑马程序员--多线程之整理笔记续
--------- android培训、java培训、期待与您交流! ----------
1线程之学习
1.6线程间的通信
1.6.1概念及示例
线程间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同。线程间通讯--等待唤醒机制
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Res 2 { 3 private String name; 4 private String sex; 5 private boolean flag = false; 6 public synchronized void set(String name,String sex) 7 { 8 if(flag) 9 try{this.wait();}catch(Exception e){} 10 this.name =name; 11 this.sex = sex; 12 flag = true; 13 this.notify(); 14 } 15 public synchronized void out() 16 { 17 if(!flag) 18 try{this.wait();}catch(Exception e){} 19 System.out.println(name+"........" +sex); 20 flag = false; 21 this.notify(); 22 } 23 } 24 class Input implements Runnable 25 { 26 Res r; 27 Input(Res r) 28 { 29 this.r = r; 30 } 31 public void run() 32 { 33 int i = 0; 34 while(true) 35 { 36 37 if(i==0) 38 r.set("mike","man"); 39 else 40 r.set("丽丽","女"); 41 i = (i+1)%2; 42 } 43 44 } 45 } 46 class Output implements Runnable 47 { 48 Res r; 49 Output(Res r) 50 { 51 this.r = r; 52 } 53 public void run() 54 { 55 while(true) 56 { 57 System.out.println(r.name + "..." + r.sex); 58 } 59 } 60 } 61 class InputOutputDemo 62 { 63 public static void main(String[] args) 64 { 65 Res r = new Res(); 66 67 new Thread(new Input(r)).start(); 68 new Thread(new Output(r)).start(); 69 /* 70 Input in = new Input(r); 71 Output out = new Output(r); 72 Thread t1 = new Thread(in); 73 Thread t2 = new Thread(out); 74 t1.start(); 75 t2.start(); 76 */ 77 } 78 }
1.6.2等待唤醒方法
- wait();
- notify();
- notityAll();
这三个方法都使用在同步中,因为要对持有监视器(锁)的线程操作,而只有同步才具有锁,所以要使用在同步中。
- 为什么这些操作线程的方法要定义Object类中呢?
- 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程的锁,
只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
不可以对不同锁中的线程进行唤醒。 - 也就是说,等待和唤醒必须是同一个锁。
- 而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
-
sleep和wait相同之处:释放CPU执行权,停止调用该方法线程的运行。
他们不同之处:
1.sleep方法没有释放锁,而wait方法释放了锁。
2.wait只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用,。
3.唤醒的方式不同,sleep方法时等待一定的时间之后,自动醒来进入到可运行状态;调用了wait方法时,必须要采用notify()和notifyAll()方法才能唤醒该进程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 对于多个生产者和消费者。 3 为什么要定义while判断标记。 4 原因:让被唤醒的线程再一次判断标记。 5 为什么定义notifyAll, 6 因为需要唤醒对方线程。 7 因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。 8 */ 9 class ProducerConsumerDemo 10 { 11 public static void main(String[] args) 12 { 13 Resource r = new Resource(); 14 15 Producer pro = new Producer(r); 16 Consumer con = new Consumer(r); 17 Thread t1 = new Thread(pro); 18 Thread t2 = new Thread(pro); 19 Thread t3 = new Thread(con); 20 Thread t4= new Thread(con); 21 22 t1.start(); 23 t2.start(); 24 t3.start(); 25 t4.start(); 26 } 27 } 28 class Resource 29 { 30 private String name; 31 private int count = 1; 32 private boolean flag = false; 33 34 public synchronized void set(String name) 35 { 36 while(flag) 37 try{this.wait();}catch(Exception e){} 38 this.name = name + "....."+ count++; 39 System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); 40 flag = false; 41 this.notifyAll(); 42 } 43 public synchronized void out() 44 { 45 while(!flag) 46 try{this.wait();}catch(Exception e){} 47 System.out.println(Thread.currentThread().getName+"...消费者...."+this.name); 48 flag = false; 49 this.notifyAll(); 50 } 51 } 52 class Producer implements Runnable 53 { 54 private Resource res; 55 Producer(Resource res) 56 { 57 this.res = res; 58 } 59 public void run() 60 { 61 while(true) 62 { 63 res.set("+商品+"); 64 } 65 } 66 } 67 class Consumer implements Runnable 68 { 69 private Resource res; 70 Consumer (Resource res) 71 { 72 this.res = res; 73 } 74 public void run() 75 { 76 while(true) 77 { 78 res.out(); 79 } 80 } 81 }
1.7停止线程
- stop()方法已经过时。
- 如何停止线程呢?只有一种方法,就是使run()方法结束。
那又怎样才能使run()方法结束呢?
- 开启多线程运行时,运行代码通常是循环结构。那么只要控制住循环,使循环结束,那么run方法也就自然而然地结束了,亦即线程结束。
- 怎样才能使冻结的线程回复到运行状态呢?
- Thread类提供该方法interrupt()对冻结状态进行清除。强制让线程恢复到运行状态中来,跳到循环结构,进而使操作标记控制循环使线程结束。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class StopThread implements Runnable { private boolean flag = true; public void run() { while(flag) { try { wait(); } catch(InterruptedException e) { System.out.println(Thread.curreatThread().getName()+"......run"); flag = false; } } } public void changeFlage() { flag = false; } } class StopThreadDemo { public static void main(String[] args) { StopThread st = new StopThread(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); int num = 0; while(true) { if(num++ = 60) { //st.changeFlag(); t1.interrupt();// t2.interrupt(); break; } } } }
1.8join()方法的使用
join方法定义在Thread类中,则调用者必须是一个线程
先定义一个关系:两个线程的关系是一个线程由另外一个线程生成并起动,所以我们暂且认为第一个线程叫做“子线程”,另外一个线程叫做“主线程”。
1.8.1什么时候使用join()方法?
-
主线程生成并起动了子线程,而子线程里要进行大量的耗时的运算(这里可以借鉴下线程的作用),
-
当主线程处理完其他的事务后,需要用到子线程的处理结果,这个时候就要用到join();方法了。
1.8.2join()方法的作用
- 借鉴下API里的说法:“等待该线程终止。
- 解释一下,是主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。(Waits for this thread to die.)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Demo implements Runnable 2 { 3 public void run() 4 { 5 for(int i=0;i<70;i++) 6 { 7 System.out.println(Thread.currentThread().getName()+"..."+i); 8 } 9 } 10 } 11 class JoinDemo 12 { 13 public static void main(String[] args) 14 { 15 Demo d = new Demo(); 16 Thread t1 = new Thread(d); 17 Thread t2 = new Thread(d); 18 t1.start(); 19 t1.join(); 20 t2.start(); 21 22 for(int i=0;i<80;i++) 23 { 24 System.out.println("main....."+i); 25 } 26 System.out.println("over"); 27 } 28 }
1.8.3yield()方法
- yield方法 暂停当前正在执行的线程对象 并执行其他的线程
1.9锁LOCK用法
1.9.1同步与锁lock
- java.util.concurrent.locks包中。提供了一个接口Lock。替代了同步。
- 同步是对锁的操作(获取锁,释放锁)是隐式的。
- 而Lock接口提供了对锁的显示操作。
- lock():获取锁
- unlock():释放锁。
- Condition接口替代了Object中的操作监视器的方法。wait,notify,notifyAll.
- Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象
- 以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。
- 其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
1.9.2Lock的出现好处:
- 可以在Lock锁上添加多组操作监视器的对象。
- 这样就可以实现本方只唤醒对方。
- ReentrantLock:一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的
- 隐式监视器锁相同的一些基本行为和语义,但功能更强大。
- ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,
- 调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。
- 可以使用 isHeldByCurrentThread() 和 getHoldCount()方法来检查此情况是否发生。
优化生产者消费者线程
import java.util.concurrent.locks.*; class Res { private String name; private int count = 1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition con1 = lock.newCondition(); private Condition con2 = lock.newCondition(); public /*synchronized*/ void set(String name) { //获取锁。 try { lock.lock(); while(flag) try{con1.await();}catch(Exception e){} this.name = name+"---"+count; count++; System.out.println(Thread.currentThread().getName()+"--生产者--"+this.name); flag = true; con2.signal(); } finally{ //释放锁。 lock.unlock(); } } public void out() { try { lock.lock();
1.10线程的其它方法
toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
setPriority():返回线程的优先级。
setName():改变线程名称,使之与参数 name 相同。
public Thread(String name)
public Thread(Runnable target,String name)
public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
d2.setDaemon(true);//要在线程开始之前设置,不然就会抛出异常。
1.11多种方法创建不同线程
public class ThreadDemo { public static void main(String[] args) { //第一种方法 new Thread(){ public void run(){ for(int i= 0;i<100;i++){ System.out.println(Thread.currentThread().toString()+"AAA"+i); } } }.start(); //第二种方法 Runnable r = new Runnable(){ public void run(){ for(int i= 0;i<100;i++){ System.out.println(Thread.currentThread().toString()+"BBB"+i); } } }; new Thread(r).start(); for(int i= 0;i<100;i++){ System.out.println(Thread.currentThread().toString()+"CCC"+i); } }
面试中的常见问题:
wait方法和sleep方法有什么区别?
- 要从锁和CPU的执行权来进行区分。
- sleep():释放CPU的执行权,但是不释放锁。
- wait(): 释放CPU的执行权,也释放锁。
--------- android培训、java培训、期待与您交流! ----------
详细请查看:http://edu.csdn.net/heima/