黑马程序员_线程间的通信

来源:互联网 发布:广州数控模拟软件 编辑:程序博客网 时间:2024/05/21 09:04

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

今天学习了毕向东老师基础视频当中的线程间的通信这部分内容,在前一天的视频当中我已基本了解了线程的应用。其中实现继承的方法有extends Thread和implements Runnable两种方法,其中我们都需要去覆写run()方法,调用线程使用的start()方法。

老师先是通过卖票这个需求,要求有多个窗口卖100张票,先是通过代码的演示给我看到多线程的运行出现的安全问题,其中出现了票-1,-2张票的错误,给了我们思考空间,老师逐层解决引出了synchronized()同步这个概念,代码演示解决了这样的一个问题,但是老是需要判断锁比较耗资源,进而我们需要同步函数,同时举例了银行储户的案例额,但是我们要明确多线程的运行代码,同时又是需要共享数据的,但是同步函数我们用什么锁呢?我们又用2个线程卖票的代码实现一个线程用同步代码快另一个用同步函数证明了同步函数其实是用this这个锁即谁调用谁是锁;下面就介绍了多线程下的单例,懒汉式同步的概念;当然我们在学习前面代码当中未碰到同步死锁的问题,老师说面试时需要写一个同步的代码,然而死锁的情况之一就是同步的嵌套,最后通过一个死锁的例子,即用到了同步嵌套,展示了其中的原理。

通过第一天的复习,感觉线程这一快内容还没有真正的理解,带着些疑问和问题看了第二天的线程。第一个讲的例子就是用2个线程,一个线程去输入姓名和年龄,另一个线程去输出,逐层的深入,一步步去优化这个代码,之中引入了同步中的一些方法,等待唤醒机制,wait(),notify(),notifyAll(),在实现了这些方法之后,就是需要去明确线程上的锁,即监视器,也是此例的重点;最经典的生产者和消费者的例子也在视频中讲解,最后在面向对象的思想下引入了jdk1.5之后的同步和锁封装成了对象,有Lock接口,lock()获取锁和unlock释放锁的方法,有Condition接口,await(),signal(),signalAll()方法,加入代码中学会使用。最后介绍了wait()和sleep()的区别,结束线程的方法,stop()方法(已过期)和run方法的结束,任务中有循环,控制住循环要用到标记,使用interrupt()将线程从冻结状态恢复到正常状态,但是要记得处理异常,最后还有join()和yield()方法的使用。

线程间的通信这块内容讲完之后,我去试着回想老师上课讲的实例,尝试着去自己打代码,解决了很多在学习当中的时候遇到的问题,在回头去看代码又有了很多的收获。

下面是今天我需要注意的一些小知识点和一些经典代码:

JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。
1,执行main函数的线程,
该线程的任务代码都定义在main函数中
2,负责垃圾回收的线程。

线程安全问题产生的原因:
1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条。


同步函数和同步代码块的区别:
同步函数的锁是固定的this。
同步代码块的锁是任意的对象。

静态的同步函数使用的锁是  该函数所属字节码文件对象 
可以用 getClass方法获取,也可以用当前  类名.class 表示。


多线程下的单例
//饿汉式  
class Single
{
private static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}


//懒汉式
加入同步为了解决多线程安全问题。
加入双重判断是为了解决效率问题。

class Single
{
private static Single s = null;


private Single(){}


public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
// -->0 -->1
s = new Single();
}
}
return s;
}
}
class  SingleDemo
{
public static void main(String[] args) 
{
System.out.println("Hello World!");
}
}


1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
2,notify():唤醒线程池中一个线程(任意).
3,notifyAll():唤醒线程池中的所有线程。
这些方法都必须定义在同步中。
因为这些方法是用于操作线程状态的方法。
必须要明确到底操作的是哪个锁上的线程。

jdk1.5以后将同步和锁封装成了对象。 
并将操作锁的隐式方式定义到了该对象中,
将隐式动作变成了显示动作。
Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。
同时更为灵活。可以一个锁上加上多组监视器。
lock():获取锁。
unlock():释放锁,通常需要定义finally代码块中。
Condition接口:出现替代了Object中的wait notify notifyAll方法。
将这些监视器方法单独进行了封装,变成Condition监视器对象。
可以任意锁进行组合。
await();
signal();
signalAll();


停止线程:
1,stop方法。
2,run方法结束。
怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。
控制循环通常就用定义标记来完成。
但是如果线程处于了冻结状态,无法读取标记。如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。 
当时强制动作会发生了InterruptedException,记得要处理



//生产者和消费者以及JDK1。5后以后的演示

class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)//  
{
while(flag)
try{this.wait();}catch(InterruptedException e){}//   t1    t0

this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
count++;//2 3 4
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
flag = true;
notifyAll();
}


public synchronized void out()//  t3
{
while(!flag)
try{this.wait();}catch(InterruptedException e){}//t2  t3
System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
flag = false;
notifyAll();
}
}

class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}

class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}

class  ProducerConsumerDemo
{
public static void main(String[] args) 
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();
}
}

JDK1.5以后的生产者和消费者:

class Resource
{
private String name;
private int count = 1;
private boolean flag = false;

// 创建一个锁对象。
Lock lock = new ReentrantLock();

//通过已有的锁获取该锁上的监视器对象。
// Condition con = lock.newCondition();

//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
Condition producer_con = lock.newCondition();
Condition consumer_con = lock.newCondition();

public void set(String name)//  t0 t1
{
lock.lock();
try
{
while(flag)
// try{lock.wait();}catch(InterruptedException e){}//   t1    t0
try{producer_con.await();}catch(InterruptedException e){}//   t1    t0

this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
count++;//2 3 4
System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
flag = true;
// notifyAll();
// con.signalAll();
consumer_con.signal();
}
finally
{
lock.unlock();
}

}

public  void out()// t2 t3
{
lock.lock();
try
{
while(!flag)
// try{this.wait();}catch(InterruptedException e){}//t2  t3
try{cousumer_con.await();}catch(InterruptedException e){}//t2  t3
System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
flag = false;
// notifyAll();
// con.signalAll();
producer_con.signal();
}
finally
{
lock.unlock();
}

}
}

class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}

class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}

class  ProducerConsumerDemo2
{
public static void main(String[] args) 
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);

Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start();

}
}

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

原创粉丝点击