现在的位置: 首页 > 综合 > 正文

再谈java线程以及经典的生产者,消费者问题

2012年08月04日 ⁄ 综合 ⁄ 共 3853字 ⁄ 字号 评论关闭

进程是一个静态的概念。

线程是一个进程里面的不同的执行路径。

java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的进程)。抢占式调度模型就是许多线程处于可以运行状态(等待状态),但实际上只有一个线程在运行。该线程一直运行到它终止进入可运行状态(等待状态),或者另一个具有更高优先级的线程变成可运行状态。在后一种情况下,低优先级的线程被高优先级的线程抢占,高优先级的线程获得运行的机会。Java线程调度器支持不同优先级线程的抢先方式,Java线程调度器本身不支持相同优先级线程的时间片轮换。它依赖于Java运行时系统所在的操作系统:如果操作系统支持时间片的轮换,则线程调度器就支持相同优先级线程的时间片轮换。

 

在同一个时间点,一个cpu只能支持一个线程。Java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在CPU上运行。

 

线程的启动必须使用Thread类的start()方法。不能在主线程main里直接调用run()。

 

创建线程的方法:

1.      定义线程实现Runnable接口

2.      Thread类继承。

class Runner1 implements Runnable

class Runner1
extends Thread

 

启动线程的方式:

1.      通过Thread

Thread t = new Thread(r);

t.start();

 

如果是使用class Runner1
extends Thread
来创建线程,可以通过如下方法来启动线程。因为只有Thread类有start方法。

2.      直接Runner1 r =
new Runner1();

r.start();

3.      通过Thread (父类指向子类的对象)

Thread t = new Runner1();

t.start();

 

sleep()会抛出interruptedException
必须try catch

可以用interrupt打断。

 

使用join()的时候,相当于方法调用。也就是说,使用了join方法的时候,先执行完使用了join的线程。相当于是说,使用了join线程的优先级最高。必须等到使用了join的线程执行完。join()同样会抛出interruptedException。必须try
catch

 

yield()就是执行到yield的时候让出一下cpu时间,但是只让出一次。

 

线程同步:线程同步的含义就是在于,不同的线程要访问同一个对象,这部分被称为critical sections

同步有两种方式:同步块和同步方法

Synchronized可以锁定当前对象。一个线程已经进入到被锁定的区域,不可以有别的线程进入。

解决死锁的方式:把锁的粒度加粗一些。也就是说,尽量锁定一个对象,不要锁定两个对象。

Synchronized锁定的是代码,而不是某个变量。也就是说,别的线程依然可以访问这个变量,只是不能通过锁定的代码部分对变量进行值的改变。但是可以通过别的方法改变变量的值。

锁定问题:加了锁定,效率变低。不加锁定,可能会出现数据不一致的错误。

程序中让线程的终止,一般不用stop方法,常用的是设置一个flag变量,然后结合interrupt()方法。

如果线程已经运行起来,又阻塞了,为了让线程停止:

首要考虑采用join()方法,正常停止。

再考虑使用exception的方式停止。

 

生产者,消费者问题。其实就是一个堆栈问题当中用到了waitnotifynotifyAll

有生产者,负责生产。

消费者,负责消费。

//每个生产者或者消费者都是一个线程。

 

//主类。

publicclass ProducerConsumer {

    publicstaticvoid main(String[] args) {

       SyncStack ss = new SyncStack();

       Producer p = new Producer(ss);

       Consumer c = new Consumer(ss);

       //三个生产者,一个消费者

       new Thread(p).start();

       new Thread(p).start();

       new Thread(p).start();

       new Thread(c).start();

    }

}

 

//产品

class WoTou {

    int id;

    WoTou(int id) {

       this.id = id;

    }

    public String toString() {

       return"WoTou :" + id;

    }

}

 

//堆栈类

class SyncStack {

   

    //栈顶指针

    int index = 0;

    //栈数组,大小为6

    WoTou[] arrWT = new WoTou[6];

   

    //压栈由生产者调用。必须是同步方法。

    publicsynchronizedvoid push(WoTou wt) {

       //满了,栈顶指针指向栈最顶部。就阻塞。

       //必须是同步方法才可以wait。如果方法没有注明synchronized,会编译出错。

       while(index == arrWT.length) {

           try {

              //this是当前对象正在访问的线程,wait

              //wait必须被人唤醒,和sleep不一样,自己醒不了。

              this.wait();

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

       }

       //唤醒消费者的线程

       this.notifyAll();

      

       //压栈

       arrWT[index] = wt;

       //指针上升

       index ++;

    }

   

    //出栈由消费者调用。必须是同步方法。

    publicsynchronized WoTou pop() {

       //空了,栈顶指针指向栈最底部。就阻塞。必须是同步方法才可以wait

       //必须用while,不能用if

       while(index == 0) {

           try {

              this.wait();

           } catch (InterruptedException e) {

              e.printStackTrace();

           }

       }

      

       this.notifyAll();

       //指针下移

       index--;

       //拿到产品

       return arrWT[index];

    }

}

 

//生产者实现runnable

class Producer
implements Runnable {

    SyncStack ss = null;

    Producer(SyncStack ss) {

       this.ss = ss;

    }

   

    publicvoid run() {

       //每个人最多生产20个馒头

       for(int i=0; i<20; i++) {

           //生产一个产品,并指定一个id

           WoTou wt = new WoTou(i);

           //生产好了以后压栈

           ss.push(wt);

System.out.println("生产了:" + wt);

           try {

              //随机睡眠一段时间

              //控制睡眠的时间

              Thread.sleep((int)(Math.random() * 200));

           } catch (InterruptedException e) {

              e.printStackTrace();

           }         

       }

    }

}

 

//消费者

class Consumer
implements Runnable {

    SyncStack ss = null;

    Consumer(SyncStack ss) {

       this.ss = ss;

    }

   

    publicvoid run() {

       //每个人最多消费20个馒头

       for(int i=0; i<20; i++) {

           //消费就是出栈

           WoTou wt = ss.pop();

System.out.println("消费了: " + wt);

           try {

              //随机睡眠一段时间

              //控制睡眠的时间

              Thread.sleep((int)(Math.random() * 1000));

           } catch (InterruptedException e) {

              e.printStackTrace();

           }         

       }

    }

}

抱歉!评论已关闭.