视频基础之线程通讯

来源:互联网 发布:逛淘宝网 编辑:程序博客网 时间:2024/06/08 14:58


一、线程间通讯:

多个线程在操作同一个资源,但是操作的动作不同。

wait()-------notify( )---notifyAll( )  都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才有锁。

 

1、为什么这线程的方法定义在Object类中呢?

因为这些方法在操作同步线程时,都必须标识他们所操作线程只有的锁,只有同一个锁上的被等待线程,才可以被同一个锁上notify所唤醒。不可以对不同锁中的线程进行唤醒,也就是说等待和唤醒必须是同一把锁。

而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。

2、wait( )是一个方法,隶属于Object类

  用法:publicvoid wait( ){throw new Exception( )}

   在此处无法throw 只能try

 

二、生产者和消费者

需求:多个生产者和多个消费者,生产者生产商品,消费者消费商品

      任意一个生产者生产一次,则任意一个消费者消费一次,交替进行;

思路:1、定义一个操作资源,生产者和消费者对其进行操作

         其中包括两个构造函数:生产商品和消费商品

      2、定义生产者实现Runnable接口以便多线程

      3、定义消费者实现Runnable接口以便实现多线程、

      4、创建主函数,建立两个生产者和两个消费者

class Resource{  private String name;       //声明一个name  private int count=1;        //初始化序号  private Boolean flag=false;   //初始化标记为假  public synchronized voidset(String name)      //闯进生产商品构造函数  {while(flag)      //判断标记是否为真,若为真则在此等待标记为假的对象运行,唤醒后判断标记 try{this.wait();}catch(Exception e){ }      //等待函数this.name=name+”….”+count++;   //商品名称加序号赋值给本类声明的nameSystem.out.println(Thread.currentThread().getName()+“..生产者..”+this.name);//获取正在执行线程对象名称加我们自定义的商品名称flag=true;//商品生产完成将标记更改为真this.notifyAll( );//唤醒所有正在等待的进程,}publicsynchronized void out( )  //{  while(!flag)    try{this.wait( );}catch(Exception e){ }  System.out.println(Thread.currentThread().getName()+”..消费者…….”+this.name);  flag=false;  this.notifyAll( );}}class Producer implements Runnable  //创建生产者类{  private Resourse res;   //声明Resource类的res  Producer(Resouece res){  this.res=res;}public void run()  //创建线程,复写runnable中的run函数{  while(true)  {    res.set(“商品”);//调用res对象中的set函数}}}class Consumer implements Runnable//穿件消费者类{  Private Resource res;  Consumer (Resource res)  {    this.res=res;}public voidrun(){  while(true)  {    res.out();}}}class ResourceDemo{  public static voidmain(String[ ] args) //主函数  {Resource r=new Resource();//创建资源对象Producer p=new Producer(r);//创建生产者对象Consumer c=new Consumer(r);//创建消费者对象Thread p1=new Thread(p);Thread p2=new Thread(p);Thread c1=new Thread(c);Thread c2=new Thread(c);p1.start();p2.start();c1.start();c2.start();}}


  1、为什么要定义while判断标记呢?

     因为让被唤醒的线程再一次判断标记

  2、为什么定义notifyAll?

     因为需要唤醒对方的线程。如果用notify容易出现只唤醒本线程的情况,导致程序中的所有线程都在等待。

 

三、1.5版本后提供了锁对象以及等待挂起封装函数

1、将同步synchroized替换成现实lock操作

2、将Object中的wait,notifyAll替换成了condition对象,该对象可以lock锁进行获取

3、在该实例中,实现了本方只唤醒对方的操作;

import java.util.concurrent.locks.*;//引入locks包

class Resource

{

 private String name;       //声明一个name

 private int count=1;        //初始化序号

 private Boolean flag=false;   //初始化标记为假

  privateLock lock=new ReentrantLock();   //使用解锁函数建立对象

 private Condition condition_pro=lock.newCondition();//建立等待解除等待对象

  privateCondition condition_con=lock.newCondition();

 

 public void set(String name) throws InterruptedException     //await是抛出异常结构

  {

     lock.lock();//调用锁,锁住

     try

     {

  while(flag)

      condition_pro.await();//抛出异常,没有try因此要throws

  this.name=name+”….”+count++;   //商品名称加序号赋值给本类声明的name

System.out.println(Thread.currentThread().getName()+“..生产者..”+this.name);

flag=true;//商品生产完成将标记更改为真

  condition_con.signal();//唤醒对方condition_con线程

}

finally

{

  lock.unlock();//解除本锁

}

}

public void out( ) throws InterruptedException //

{

  lock.lock();

  try

  {

while(!flag)

    condition_con.await();

  System.out.println(Thread.currentThread().getName()+”..消费者…….”+this.name);

  flag=false;

         condition_pro.signal();

}

finally

{

        lock.unlock();

}

}

}

class Producer implements Runnable   //创建生产者类

{

 private Resourse res;   //声明Resource类的res

 Producer(Resouece res)

{

 this.res=res;

}

public void run( )  //创建线程,复写runnable中的run函数

{

 while(true)

  {

try

{

      res.set(“商品”);//调用res对象中的set函数

}

catch(InterruptedExceptione)

{}

}

}

}

class Consumer implements Runnable//穿件消费者类

{

 Private Resource res;

 Consumer (Resource res)

  {

   this.res=res;

}

public void run()

{

 while(true)

  {

try

{

     res.out();

}

catch(InterruptedExceptione)

{}

}

}

}

class ResourceDemo

{

 public static void main(String[ ] args) //主函数

  {

Resource r=new Resource();//创建资源对象

Producer p=new Producer(r);//创建生产者对象

Consumer c=new Consumer(r);//创建消费者对象

Thread p1=new Thread(p);

Thread p2=new Thread(p);

Thread c1=new Thread(c);

Thread c2=new Thread(c);

p1.start();

p2.start();

c1.start();

c2.start();

}

}

 

四、线程结束

线程的结束之前使用stop方法,现在已经过时,使用另一种run方法结束。

思路:开启多线程运行,运行代码通常是循环结构,只要能够控制住循环,就可以让run方法结束,也就是线程结束。

 

特殊情况:当线程处于冻结状态,就不会读取到标记,程序就不会结束。

class StopThread implements Runnable

{

 private booleas flag=true;

 public synchronized void run()

{

  while(flag)

  {

    try

    {

      wait();

}

catch(InterruptedException e)

{

 System.out.println(Thread.currentThread().getName()+”…Exception”);

  flag=false;//对冻结进行清除

}

System.out.println(Thread.currentThread().getName()+”..run”);

}

}

}

class StopThreadDemo

{

 public static void main(String[] args)

  {

StopThreadst=new StopThread();

Thread t1=newThread(st);

Thread t2=newThread(st);

t1.start();

t2.start();

int num=0;

while(true)

{

  if(num++=60)

  {

    t1.interrupt();//对冻结进行解除

    t2.interrupt();

}

System.out.println(Thread.currentThread().getName()+”…..”+num);

}

System.out.println(“over”);

}

}

当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结进行清除。强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束

Thread类提供该方法interrupt();

 

 

五、守护线程(主线程结束该线程结束)

将该线程标记为守护线程或用户线程,当正在运行的线程都是守护线程时,Java退出运行。

该方法必须在启动线程前调用。.setDaemon(true);

class StopThread implements Runnable

{

 private Boolean flag=true;

public synchronized void run()

{

  while(flag)

   System.out.println(Thread.currentThread().getName()+”...run”);

}

class ShouHuDemo

{

 public static void main(String[] args)

{

  StopThread st=newStopThread();

  Thread t1=new Thread(st);

  Thread t2=new Thread(st);

  t1.setDaemon(true);//守护线程

  t2.setDaemon(true);

t1.start();

t2.start();

int num=0;

while(true)

{

    if(num++==60)

      break;

    System.out.println(Thread.currentThread().getName()+”….”+num);

}

System.out.println(“over”);

 

}

}

 

六、Join函数

主线程让Join线程先运行:join也是一个需要抛或try的构造函数

 

特点:当A线程执行到了B线程的Join()方法时,就会等待,等B线程都执行完,A才会执行。

Join可用来临时加入线程。

 

class Demo implements Runnable

{

public void run()

{

  for(int x=0;x<70;x++)

   System.out.println(Thread.currentThread().getName)+”…”+x);

}

}

class JoinDemo

{

 public static void main(String[] args) throws Exception//Join对应函数抛出异常

{

 Demo d=new Demo();

 Thread d1=new Thread(d);

 Thread d2=new Thread(d);

 d1.start();

 d1.join();//Join函数抢夺执行权,d1结束后主线程在运行

 d2.start();

 for(int x=0;x<100;x++)

  {

   System.out.println(Thread.currentThread().getName()+”…..”+x);

}

System.out.println(“over”);

}

}

七、多线程优先级、临时停止

多线程优先级即可理解为抢夺CPU执行权能力的大小,1-10,

10是MAX_PRIORITY

5是NORM_PRIORITY

1是MIN_PRIORITY

调用方式:d1.setPriority(Thread. MAX_PRIORITY);

临时停止:   Thread.yield();暂停当前正在执行的线程对象,并执行其他线程

class Demo implements Runnable

{

public void run()

{

 for(int x=0;x<70;x++)

   {

System.out.println(Thread.currentThread().getName)+”…”+x);

Thread.yield();//临时停止

   }

}

}

class YouXianDemo

{

 public static void main(String[] args)           // throws Exception//Join对应函数抛出异常

{

 Demo d=new Demo();

 Thread d1=new Thread(d);

 Thread d2=new Thread(d);

 d1.start();

 d1.setPriority(Thread.MAX_PRIORITY);//更改d1的优先级

               //d1.join();//Join函数抢夺执行权,d1结束后主线程在运行

 d2.start();

 for(int x=0;x<100;x++)

  {

   System.out.println(Thread.currentThread().getName()+”…..”+x);

}

System.out.println(“over”);

}

}

0 0