多线程

 1>进程

 2>线程

/*


进程:正在进行中的程序(直译),其实就是该应用程序在内存中分配的空间。

 


线程:是在进程中负责程序执行的一条路径。负责程序执行的。

在进程中至少有一个线程在运行。 


多线程:当有多部分代码需要同时运行时,就需要开辟多条执行路径来完成。

这时该程序就是多线程程序。


多线程解决了,让多部门代码同时运行的问题。





 3>多线程存在的意义。

 4>线程的创建方式

 5>多线程的特性


/*

通过api文档发现Thread类中描述中。

有两种创建方式。

1,继承Thread类,并复写run方法。


每一个线程都应该有自己的任务,而且任务都会定义在指定的位置上。


主线程的任务都定义在main方法中。

自定义线程的任务都定义在了run方法中。 


Thread t = new Thread();

t.start();//这种开启只能调用Thread类中自己的run方法。而该run方法中并未定义自定义的内容。



我还需要创建线程,还要让线程执行自定义的任务。

所以可以复写run方法。前提必须是继承Thread类。


而继承了Thread后,该子类对象就是线程对象。 

~~~~~~~~~~

*/

class Demo extends Thread

{

   private String name;

   Demo(String name)

   {

       this.name = name;

    }

   public void run()

  {

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

       {

            System.out.println("name...."+x+"....."+name);

        }

    }

}


class ThreadDemo 

{

    public static void main(String[] args) 

    {

        //创建线程对象。

        Demo d1 = new Demo("小强");

        Demo d2 = new Demo("旺财");


        //开启线程。让线程运行起来。

        d1.start();

        d2.start();


        d1.run();

        d2.run();

     }

}


多线程内存图:

 wKiom1PfKwmQIUm2AADWUdtQ0PI323.jpg

/*

调用run方法和调用start方法的区别?


如何定义线程名称。如果将线程名称打印在控制台上。



class Demo extends Thread

{

//private String name;

Demo(String name)

{

//this.name = name;

super(name);

}

public void run()

{

//System.out.println(3/0);

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

{

System.out.println("name="+"::::"+getName());

}

}

}


class  ThreadDemo2

{

public static void main(String[] args) 

{

Demo d1 = new Demo("小强");

Demo d2 = new Demo("旺财");

d1.start();

d2.start();

//int[] arr = new int[2];

//System.out.println(arr[2]);

//System.out.println("over");


System.out.println(Thread.currentThread().getName());

}

}



-----------


JVM中的多线程了解。


jvm中也一样是多线程程序,

只要有一个线程负责着程序的执行。

又有一个线程负责着垃圾的回收。

这个是同时进行的。



结论:

每一个线程都有自己的运行代码,这个称之为线程的任务。


对于每一个线程便于识别都有自己的名称。

比如负责从主函数执行程序代码的线程,称之为 主线程。main thread.

主线程运行的代码都定义在主函数中。



负责收垃圾的线程:垃圾回收线程。



发现运行结果不一样。

多线程的随机性造成的,因为cpu的快速切换的原因。



final finally  finalize

*/



class Test extends Object

{

/*

重写了垃圾回收器调用的方法

*/

public void finalize()

{

System.out.println("test ok");

}

}


class Demo

{

public static void main(String[] args) 

{

new Test();

new Test();

new Test();

new Test();

new Test();

System.gc();//调用了一次垃圾回收器。

System.out.println("Hello World!1");

System.out.println("Hello World!2");

System.out.println("Hello World!3");

System.out.println("Hello World!4");


}

}


创建线程方式一

1.子类覆盖父类中的run方法,将线程运行的代码存放在run中。

2.建立子类对象的同时线程也被创建。

3.通过调用start方法开启线程。

wKioL1O8pEujWybCAAFc0XJ0t6Q471.jpg



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


*/

创建线程方式二

实现Runnable接口

 1>子类覆盖接口中的run方法。

 2>通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。

 3>Thread类对象调用start方法开启线程。

思考:为什么要给Thread类的构造函数传递Runnable的子类对象?


线程安全问题

导致安全问题的出现的原因:

 1>多个线程访问出现延迟。

 2>线程随机性  。

注:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。


/*

创建线程的第二种方式。实现Runnable接口。


1,实现Runnable接口。

2,覆盖run方法。

3,通过Thread类创建线程对象。

4,将Runnable接口的子类对象作为实参传递给Thread类中的构造函数。

因为要让线程去运行指定的对象的run方法。

5,调用start方法开启线程,并运行Runnable接口子类的run方法。



第二种实现Runnable接口创建线程思想:

将线程任务和线程对象进行解耦,将线程任务单独封装成对象。


另,实现Runnable接口可以避免单继承的局限性。


所以建议创建多线程,都是用实现Runnable接口的方式。






*/


class Ticket implements Runnable

{

    private int num = 100;

    public void run()

   {

       while(true)

       {

          if(num>0)

          {

           //try{Thread.sleep(10);}catch(InterruptedException e){}//让线程在这里小睡,导致              了 0 -1 等错误票的产生。

            //出现了线程安全问题。

            System.out.println(Thread.currentThread().getName()+"..sale:"+num--);

           }

        }

     }

}


class ThreadDemo3_Ticket_Runnable

{

    public static void main(String[] args) 

    {

      Ticket t = new Ticket();


      Thread t1 = new Thread(t);

      Thread t2 = new Thread(t);

      Thread t3 = new Thread(t);

      Thread t4 = new Thread(t);

      t1.start();

      t2.start();

      t3.start();

      t4.start();

    }

}



/*

class Thread

{

      private Runnable target;

      Thread()

      {

      }


      Thread(Runnable target)

     {

         this.target = target;

      }


     public void run()

    {

       if(target!=null){

       target.run();

        }

      }

     public void start()

     {

          run();

      }

}



class Student impl Runnable

{

     public void run(){}

}

Student stu = new Student();

Thread t = new Thread(stu);

t.start();


*/




/*

线程安全问题。

原因:


1,多个线程在同时处理共享数据。

2,线程任务中的有多条代码在操作共享数据。


安全问题成因就是:一个线程在通过多条操作共享数据的过程中,其他线程参与了共享数据的操作。

导致到了数据的错误。



想要知道你的多线程程序有没有安全问题:

只要看线程任务中是否有多条代码在处理共享数据。



解决:

一个线程在通过多条语句操作共享数据的过程中,不允许其他线程参与运算。就哦了。


如何代码体现呢?

Java中提供了同步代码块进行引起安全问题的代码封装。


格式:

synchronized(对象)

{

//需要被同步的代码;

}



同步:

好处:解决了多线程的安全问题。

弊端:降低了效率。


同步的前提:

1,至少有两个线程在同步中。

2,必须保证同步使用的是同一个锁。



*/



class Ticket implements Runnable

{

private int num = 100;

Object obj = new Object();

public void run()

{

while(true)

{

synchronized(obj)

{

if(num>0)

{

try{Thread.sleep(10);}catch(InterruptedException e){}//让线程在这里小睡,导致了 0 -1 等错误票的产生。

//出现了线程安全问题。

System.out.println(Thread.currentThread().getName()+"..sale:"+num--);

}

}

}

}

}


class ThreadDemo4_Ticket_Safe

{

public static void main(String[] args) 

{

Ticket t = new Ticket();


Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

Thread t4 = new Thread(t);

t1.start();

t2.start();

t3.start();

t4.start();

}

}




同步(synchronized)


格式:

synchronized(对象)

{

  需要同步的代码;

}

同步可以解决安全问题的根本原因就在那个对象上。

该对象如同锁的功能。



同步的特点

同步的前提:

 1>同步需要两个或者两个以上的线程。

 2>多个线程使用的是同一个锁。

 未满足这两个条件,不能称其为同步。

 同步的弊端:

 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率.


同步函数

格式:

 在函数上加上synchronized修饰符即可。

 思考:同步函数用的是哪个锁呢?

 程序验证。




线程间通信

wKiom1O8pmTB47jqAABNJ0S7moY093.jpg

思考1:wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?

  1>这些方法存在与同步中。

  2>使用这些方法时必须要标识所属的同步的锁。

  3>锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

思考2:wait(),sleep()有什么区别?

   wait():释放cpu执行权,释放锁。

   sleep():释放cpu执行权,不释放锁


停止线程

  1>定义循环结束标记

    因为线程运行代码一般都是循环,只要控制了循环即可。

  2>使用interrupt(中断)方法

    该方法是结束线程的冻结状态,使线程回到运行状态中来。

注:stop方法已经过时不再使用


线程类的其他方法

  1>setPriority(int num)

  2>setDaemon(boolean b)

  3>join()

  4>自定义线程名称

  5>toString()


/*

线程安全问题。

原因:


1,多个线程在同时处理共享数据。

2,线程任务中的有多条代码在操作共享数据。


安全问题成因就是:一个线程在通过多条操作共享数据的过程中,其他线程参与了共享数据的操作。

导致到了数据的错误。



想要知道你的多线程程序有没有安全问题:

只要看线程任务中是否有多条代码在处理共享数据。



解决:

一个线程在通过多条语句操作共享数据的过程中,不允许其他线程参与运算。就哦了。


如何代码体现呢?

Java中提供了同步代码块进行引起安全问题的代码封装。


格式:

synchronized(对象)

{

//需要被同步的代码;

}



同步:

好处:解决了多线程的安全问题。

弊端:降低了效率。


同步的前提:

1,至少有两个线程在同步中。

2,必须保证同步使用的是同一个锁。



*/



class Ticket implements Runnable

{

private int num = 100;

Object obj = new Object();

public void run()

{

while(true)

{

synchronized(obj)

{

if(num>0)

{

try{Thread.sleep(10);}catch(InterruptedException e){}//让线程在这里小睡,导致了 0 -1 等错误票的产生。

//出现了线程安全问题。

System.out.println(Thread.currentThread().getName()+"..sale:"+num--);

}

}

}

}

}


class ThreadDemo4_Ticket_Safe

{

public static void main(String[] args) 

{

Ticket t = new Ticket();


Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

Thread t4 = new Thread(t);

t1.start();

t2.start();

t3.start();

t4.start();

}

}




/*

静态同步函数使用的锁是什么?

就是所在类的 类名.class  字节码文件对象。



*/

class Ticket implements Runnable

{

private static  int num = 100;

boolean flag = true;

Object obj = new Object();

public void run()

{

if(flag)

{

while(true)

{

synchronized(Ticket.class)//super.getClass()

{

if(num>0)

{

try{Thread.sleep(10);}catch(InterruptedException e){}

System.out.println(Thread.currentThread().getName()+"..obj:"+num--);

}

}

}

}

else

while(true)

{

this.sale();

}

}


public static synchronized/**/ void sale()//static同步函数。

{

if(num>0)

{

try{Thread.sleep(10);}catch(InterruptedException e){}

System.out.println(Thread.currentThread().getName()+"..func:"+num--);

}

}

}


class ThreadDemo5_Ticket_StaticLock

{

public static void main(String[] args) 

{

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

//Thread t3 = new Thread(t);

//Thread t4 = new Thread(t);

t1.start();

try{Thread.sleep(10);}catch(InterruptedException e){}

t.flag = false;

t2.start();

//t3.start();

//t4.start();

}

}


//饿汉式

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

s = new Single();

}

}

}

return s;

}

}


class ThreadDemo6_Single

{

public static void main(String[] args)

{

}

}




/*

同步的另一个弊端:

容易引发死锁。


开发时,尽量避免同步嵌套的情况。



*/


class Ticket implements Runnable

{

private int num = 100;

boolean flag = true;

Object obj = new Object();

public void run()

{

if(flag)

{

while(true)

{

synchronized(obj)

{

sale();

}

}

}

else

while(true)

{

this.sale();

}

}


public synchronized/**/ void sale()//同步函数。

{

synchronized(obj)

{

if(num>0)

{

try{Thread.sleep(10);}catch(InterruptedException e){}

System.out.println(Thread.currentThread().getName()+"..sale:"+num--);

}

}

}

}


class ThreadDemo7_Ticket_DeadLock

{

public static void main(String[] args) 

{

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t1.start();

try{Thread.sleep(10);}catch(InterruptedException e){}

t.flag = false;

t2.start();

}

}





class Demo implements Runnable

{

     private boolean flag;


     Demo(boolean flag)

    {

       this.flag = flag;

     }


     public void run()

     {


        if(flag)

        {

           while(true)

           {

                 synchronized(MyLock.LOCKA)

                 {

                       System.out.println("if locka");

                       synchronized(MyLock.LOCKB)

                       {

                             System.out.println("if lockb");

                        }

                 }

             }

          }

         else

         {

             while(true)

            {

                synchronized(MyLock.LOCKB)

               {

                  System.out.println("else lockb");

                  synchronized(MyLock.LOCKA)

                  { 

                      System.out.println("else locka");

                   }

                }

             }

          }

     }

}


class MyLock

{

      public static final Object LOCKA = new Object();

      public static final Object LOCKB = new Object();

}


class ThreadDemo8_DeadLock 

{

     public static void main(String[] args) 

    {

           Demo d1 = new Demo(true);

           Demo d2 = new Demo(false);

           Thread t1 = new Thread(d1);

           Thread t2 = new Thread(d2);

           t1.start();

           t2.start();

     }

}



/*

多线程间通信:多个线程处理同一资源,但是处理动作却不同。




wait():可以让当前处于等待,这时的线程被临时存储到的线程池中。

notify():唤醒线程池中任意一个等待的线程。

notifyAll():唤醒线程池中所有的等待线程。


这些方法在使用时,必须要定义在同步中,必须被所属同步的锁对象来调用。

*/


//创建一个资源描述。资源中有name sex。用于存储数据。

class Resource

{

String name;

String sex;

//定义标记,用于判断资源中是否有数据。

boolean flag;

}



//需要定义一个输入任务描述。既然是线程任务,必须实现Runnable接口。 

class Input implements Runnable

{

private Resource r;

//private Object obj = new Object();

Input(Resource r)

{

this.r = r;

}

//覆盖run方法。 

public void run()

{

int x = 0;

while(true)

{

synchronized(r)

{


if(r.flag)

try{r.wait();}catch(Exception e){}


//输入任务中必然要处理资源。要给资源中的name sex赋值。

//需要对象。对象确定吗?不确定,传递进来就哦了。输入任务一创建对象就必须有资源。

//完全可以在构造时明确资源对象。 

if(x==0)

{

r.name = "zhangsan";

r.sex = "man";

}

else

{

r.name = "小花";

r.sex = "女女女女女";

}

//赋值后,将标记改为true,说明有值。

r.flag = true;

//唤醒等待的线程。

r.notify();

}

x = (x+1)%2;


}

}

}


//需要定义一个输出任务描述。既然是线程任务,必须实现Runnable接口。 

class Output implements Runnable

{

private Resource r;

//private Object obj = new Object();

Output(Resource r)

{

this.r = r;

}

public void run()

{

while(true)

{

synchronized(r)

{

if(!r.flag)//资源中没有数据就等待。

try{r.wait();}catch(Exception e){}

System.out.println(r.name+"...."+r.sex);

//将标记改为false.

r.flag = false;

//唤醒等待的线程。其实就是唤醒了输入线程。

r.notify();


}

}

}

}



class  ThreadDemo_Resource

{

public static void main(String[] args) 

{

//1,创建资源的对象。

Resource r = new Resource();

//2,创建任务对象。

Input in = new Input(r);

Output out = new Output(r);


//3,创建线程对象。

Thread t1 = new Thread(in);

Thread t2 = new Thread(out);

//4,启动并运行线程。

t1.start();

t2.start();

}

}



class Resource

{

private String name;

private String sex;

//定义标记,用于判断资源中是否有数据。

private boolean flag;


//对外提供方法访问这些属性。

public synchronized void set(String name,String sex)

{

if(flag)

try{this.wait();}catch(Exception e){}


this.name = name;

this.sex = sex;

flag = true;

this.notify();

}


//对外提供获取方法。

public synchronized void out()

{

if(!flag)

try{this.wait();}catch(Exception e){}

System.out.println(name+"::::"+sex);

flag = false;

this.notify();

}

}



//需要定义一个输入任务描述。既然是线程任务,必须实现Runnable接口。 

class Input implements Runnable

{

private Resource r;

//private Object obj = new Object();

Input(Resource r)

{

this.r = r;

}

//覆盖run方法。 

public void run()

{

int x = 0;

while(true)

{

if(x==0)

{

r.set("zhangsan","man");

}

else

{

r.set("小花","女女女女女");

}

x = (x+1)%2;

}

}

}


//需要定义一个输出任务描述。既然是线程任务,必须实现Runnable接口。 

class Output implements Runnable

{

private Resource r;

//private Object obj = new Object();

Output(Resource r)

{

this.r = r;

}

public void run()

{

while(true)

{

r.out();

}

}

}



class  ThreadDemo2_Resource

{

public static void main(String[] args) 

{

//1,创建资源的对象。

Resource r = new Resource();

//2,创建任务对象。

Input in = new Input(r);

Output out = new Output(r);


//3,创建线程对象。

Thread t1 = new Thread(in);

Thread t2 = new Thread(out);

//4,启动并运行线程。

t1.start();

t2.start();

}

}



/*


单生产者和单消费者。等待唤醒机制。


*/



class Resource

{

//定义一个商品都有名字。

private String name;

//定义一个商品的编号。

private int count = 1;


//定义用来判断是否有商品的标记。

private boolean flag = false;

public synchronized  void set(String name)

{

if(flag)

try{wait();}catch(Exception e){}

this.name = name+"--"+count;

count++;


System.out.println(Thread.currentThread().getName()+"---生产了,"+this.name);

//将标记改为true。

flag = true;

notify();//唤醒等待的线程。 

}

public synchronized void get()

{

if(!flag)

try{wait();}catch(Exception e){}

System.out.println(Thread.currentThread().getName()+"-------消费了....."+this.name);

flag = false;

notify();

}

}


//定义生产者的任务。

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.get();

}

}

}



class ThreadDemo_Producer_Consumer 

{

public static void main(String[] args) 

{

Resource r = new Resource();

Producer pro = new Producer(r);

Consumer con = new Consumer(r);

Thread t1 = new Thread(pro);

Thread t2 = new Thread(con);

t1.start();

t2.start();

}

}



/*


多生产者和多消费者。等待唤醒机制。



产生了两个问题:


1,出现了多次连续生产,未消费,或者一个商品被消费多次。

必须要每一个被唤醒的线程判断一次标记,所以将if判断改为while判断。


2,出现了死锁。

本方唤醒了本方,导致了所以的线程都等待了。

解决方式就是,唤醒所有等待的线程。这样既唤醒了本方也唤醒对方。


虽然解决了多生产消费的问题,但是有些低效。




*/



class Resource

{

//定义一个商品都有名字。

private String name;

//定义一个商品的编号。

private int count = 1;


//定义用来判断是否有商品的标记。

private boolean flag = false;

public synchronized  void set(String name)//

{


while(flag)

try{wait();}catch(Exception e){}//t1,t2

this.name = name+"--"+count;//蛋糕1  蛋糕2 蛋糕3

count++;


System.out.println(Thread.currentThread().getName()+"---生产了,"+this.name);//生产蛋糕1 生产蛋糕2 生产蛋糕3

//将标记改为true。

flag = true;

notifyAll();//唤醒等待的线程。 

}

public synchronized void get()//

{

while(!flag)

try{wait();}catch(Exception e){}//t3.t4

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.get();

}

}

}



class ThreadDemo_Producer_Consumer2 

{

public static void main(String[] args) 

{

Resource r = new Resource();

Producer pro = new Producer(r);

Consumer con = new Consumer(r);


//创建两个生产者线程。

Thread t1 = new Thread(pro);

Thread t2 = new Thread(pro);

//创建两个消费者线程。

Thread t3 = new Thread(con);

Thread t4 = new Thread(con);

t1.start();

t2.start();

t3.start();

t4.start();

}

}



import java.util.concurrent.locks.*;



class Resource

{

//定义一个商品都有名字。

private String name;

//定义一个商品的编号。

private int count = 1;


//定义用来判断是否有商品的标记。

private boolean flag = false;


//根据jdk1.5 版本的特性,创建一个锁对象。比同步的隐式锁操作要更加的面向对象。提供了显示的锁操作。

final Lock lock = new ReentrantLock();//互斥锁。


//通过lock锁获取监视器方法对象。Condition 负责生产者的监视操作。

final Condition producer = lock.newCondition();


//在创建一个监视器方法对象。负责消费者的监视操作。

final Condition consumer = lock.newCondition();


public  void set(String name)//

{

//通过锁对象进行显示的获取锁操作。

lock.lock();

try

{

while(flag)

try{producer.await();}catch(Exception e){}//t1,t2

this.name = name+"--"+count;//蛋糕1  蛋糕2 蛋糕3

count++;


System.out.println(Thread.currentThread().getName()+"---生产了,"+this.name);//生产蛋糕1 生产蛋糕2 生产蛋糕3

//将标记改为true。

flag = true;

consumer.signal();//唤醒等待的线程。 

}

finally{

//释放锁。

lock.unlock();//定义在finally中,要求一定被释放。

}

}

public  void get()//

{

lock.lock();

try

{

while(!flag)

try{consumer.await();}catch(Exception e){}//t3.t4

System.out.println(Thread.currentThread().getName()+"------++++++-消费了....."+this.name);//消费蛋糕1

flag = false;

producer.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.get();

}

}

}


class ThreadDemo_Producer_Consumer3 

{

public static void main(String[] args) 

{

Resource r = new Resource();

Producer pro = new Producer(r);

Consumer con = new Consumer(r);


//创建两个生产者线程。

Thread t1 = new Thread(pro);

Thread t2 = new Thread(pro);

//创建两个消费者线程。

Thread t3 = new Thread(con);

Thread t4 = new Thread(con);

t1.start();

t2.start();

t3.start();

t4.start();

}

}



sleep和wait的区别?

1,sleep必须指定时间,wait可以指定可以不指定。

2,sleep和wait都可以让线程处于冻结状态,释放执行权。(相同点)

3,持有锁的线程执行sleep,不释放锁,持有锁的线程执行到wait释放锁。

4,sleep到时间会自动醒,wait没有指定时间,只能被其他线程通过notify唤醒。





class  

{

public static void main(String[] args) 

{

System.out.println("Hello World!");

}

}


class BoundedBuffer {

   final Lock lock = new ReentrantLock();

   final Condition notFull  = lock.newCondition(); 

   final Condition notEmpty = lock.newCondition(); 


   final Object[] items = new Object[100];

   int putptr, takeptr, count;


   public void put(Object x) throws InterruptedException {

     lock.lock();

     try {

       while (count == items.length) 

         notFull.await();

       items[putptr] = x; 

       if (++putptr == items.length) putptr = 0;

       ++count;

       notEmpty.signal();

     } finally {

       lock.unlock();

     }

   }


   public Object take() throws InterruptedException {

     lock.lock();

     try {

       while (count == 0) 

         notEmpty.await();

       Object x = items[takeptr]; 

       if (++takeptr == items.length) takeptr = 0;

       --count;

       notFull.signal();

       return x;

     } finally {

       lock.unlock();

     }

   } 



class BoundedBuffer {

   final Lock lock = new ReentrantLock();

   final Condition notFull  = lock.newCondition(); 

   final Condition notEmpty = lock.newCondition(); 


   final Object[] items = new Object[100];

   int putptr, takeptr, count;


   public void put(Object x) throws InterruptedException {

     lock.lock();

     try {

       while (count == items.length) 

         notFull.await();

       items[putptr] = x; 

       if (++putptr == items.length) putptr = 0;

       ++count;

       notEmpty.signal();

     } finally {

       lock.unlock();

     }

   }


   public Object take() throws InterruptedException {

     lock.lock();

     try {

       while (count == 0) 

         notEmpty.await();

       Object x = items[takeptr]; 

       if (++takeptr == items.length) takeptr = 0;

       --count;

       notFull.signal();

       return x;

     } finally {

       lock.unlock();

     }

   } 




class Demo implements Runnable

{

private String name;

Demo(String name)

{

this.name = name;

}

public void run()

{

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

{

System.out.println(Thread.currentThread().getName()+"...."+x+"...."+name);

Thread.yield();

}

}

}



class ThreadDemo_Join 

{

public static void main(String[] args) throws Exception

{

Demo d1  = new Demo("小强");

Demo d2  = new Demo("旺财");


Thread t1 = new Thread(d1);

Thread t2 = new Thread(d2);


t1.start();


//调用了t1.join();方法。


t2.start();

t1.join();//主线程等待t1线程终止。


/*for(int x=0; x<20; x++)

{

System.out.println("main......"+x);

}

*/


}

}