黑马程序员--多线程之整理笔记续

                              --------- android培训java培训期待与您交流 ----------

1线程之学习

1.6线程间的通信

1.6.1概念及示例

线程间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同。线程间通讯--等待唤醒机制

线程间通信示例
 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等待唤醒方法

  1. wait();
  2. notify();
  3. notityAll();

  这三个方法都使用在同步中,因为要对持有监视器(锁)的线程操作,而只有同步才具有锁,所以要使用在同步中。

  • 为什么这些操作线程的方法要定义Object类中呢?
  • 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程的锁,
    只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
    不可以对不同锁中的线程进行唤醒。
  • 也就是说,等待和唤醒必须是同一个锁。
  • 而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
  • sleep和wait相同之处:释放CPU执行权,停止调用该方法线程的运行。

     他们不同之处:

    1.sleep方法没有释放锁,而wait方法释放了锁。

    2.wait只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用,。

    3.唤醒的方式不同,sleep方法时等待一定的时间之后,自动醒来进入到可运行状态;调用了wait方法时,必须要采用notify()和notifyAll()方法才能唤醒该进程

经典生产者消费者线程
 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()对冻结状态进行清除。强制让线程恢复到运行状态中来,跳到循环结构,进而使操作标记控制循环使线程结束。

 

停止线程示例
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.)
join方法示例
 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接口提供了对锁的显示操作。
  1. lock():获取锁
  2. unlock():释放锁。
  • Condition接口替代了Object中的操作监视器的方法。wait,notify,notifyAll.
  • Condition 将 Object 监视器方法(waitnotifynotifyAll)分解成截然不同的对象
  • 以便通过将这些对象与任意 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/

 

 
 
posted on 2012-07-29 17:03  doublewinwin  阅读(155)  评论(0编辑  收藏  举报