线程知识点总结02

来源:互联网 发布:java获取私有属性 编辑:程序博客网 时间:2024/05/21 09:16




1、   单列设计模式:

1、恶汉式:

代码体现:

Class Single

{

Privtae static final Single s=new Single();

Private Single(){}

Public static Single getInstance()

{

Return s;

}

}

2、懒汉式:延迟加载,存在着多线程并发访问的安全问题,需要使用同步来解决安全问题,但是同步会降低效率,所以使用双重if()判断形式解决效率低的问题。

实现代码:

Class Single

{

Private Single(){}

Private static Single s=null;

Public static Single getInstance()

{

If(s==null)

{

Synchroinzed(Single.class)

{

If(s==null)

S=new Single();

}

Return s;

}

}

}

2、死锁:即同步的弊端,不是线程和进程没有了,而是不动了。

表现形式:同步嵌套的时候,使用的锁不一样,容易引发死锁。
       实现代码:

 

3、线程间通信:

其实就是多个线程在操作同一个资源,但是操作的动作不同,动作不同,意味着线程的任务是不一样的。就需要对任务对象进行单独的封装和描述。

4、等待唤醒机制:最重要的机制重点掌握

Wait():等待:让当前线程出于冻结状态,当前线程就被存储到线程池当中。

Notify();唤醒线程池中的任意一个线程,让该线程恢复到运行状态,会具备CPU的执行资格。

notifyAll():唤醒线程池中的所有等待的线程,让它们具备CPU的执行资格。

所谓的监视器:就是多线程中的锁。上面几个功能必须在同步当中,要标示清楚它所在的锁。

也就说:wait到底让哪个锁上的线程等待了,notify:到底是唤醒了哪个锁上被等待的线程。

NotifyAll:用上面的一样。

为什么是Object中的方法?

因为这些方法都是必须要标识出所属的锁,而锁是任意的对象。能被任意对象调用的方法一定定义在Object类中。一般在使用等待和唤醒时通常都得有标记。

代码优化:ResourceDemo3.java

class Resource

{

      private String name;

      private String sex;

       privateboolean flag = false;

 

       publicsynchronized void set(String name,String sex)

       {

             if(flag)

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

             this.name = name;

             this.sex = sex;

             flag = true;

             this.notify();

       }

       publicsynchronized void out()

       {

             if(!flag)

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

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

             flag = false;

             this.notify();

       }

}

 

 

class Input implements Runnable

{

      Resource r;

      Input(Resource r)

       {

             this.r = r;

       }

 

       publicvoid run()

       {

             int x = 0;

             while (true)

             {

                   if(x==0)

                          r.set("mike","nan");

                    else

                          r.set("丽丽","女女女女女");

                    x =(x+1)%2;

             }

       }

 

}

 

class Output implements Runnable

{

      Resource r;

      Output(Resource r)

       {

             this.r = r;

       }

       publicvoid run()

       {

             while(true)

             {

                   r.out();

             }

       }

}

 

class  ResourceDemo3

{

       publicstatic void main(String[] args)

       {

             Resource r = new Resource();

             Input in = new Input(r);

             Output out = new Output(r);

 

             Thread t1 = new Thread(in);

             Thread t2 = new Thread(out);

 

             t1.start();

             t2.start();

       }

}

 

4、生产者和消费者问题:

   遇到的问题:

1、出现了错误数据,是因为多生产多消费的时候,被唤醒的线程没有再次判断标记就执行了,解决时将if判断边成while循环判断,(这种方式是最安全的)

2、有了while判断后死锁了,因为本方线程唤醒的有可能还是本方线程,所以导致死锁,解决:本方必须唤醒对放才有效,notify只能唤醒一个, 还不确定,所以干脆唤醒所有的,肯定包含对象,至于被唤醒的本方会判断标记是否继续等待。

实现代码:

Class Resource

{

Prvate String name;

Private int count;

Private boolean flag;

Private synchronized void set(String name)

{

While(flag)

Try

{

This.wait();

}

Catch(Exception e){}

This.name=name+count;

Count++;

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

"...生产者"+this.name)

Flag=true;

notifyAll();

}

Public synchronized void out()

{

While(!flag)

Try{thsi.wait();}catch(Exception e){}
      System.out.println(Thread.currentThread().getName()+"....消费者"+this.name);

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;

Consumder(Resource r)

{

This,r=r;

}

Public void run()

{

While(true)

{

R.out();

}

}

}

Class ProConDemo

{

//主函数

Resource r=new Resource(0;

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

}

总结:以上解决的方式还存折弊端,因为唤醒了所有的线程,但是如果唤醒了本方的,还是要进行本方的判断,这就会降低效率,所以这里我们在学习一种可以避免这种情况的方法。

Lock接口:

JDK1.5版本后对多线程中的内部细节进行了升级改良,在java.util.concurrent.locks包中提供了一个lock接口。比同步应用的更为广泛,lock接口中提供了loc()获取锁,unlock释放锁的操作,这样更符合面向对象的思想,将锁这种事物封装成了对象。

Eg:

Public void run()

{

Synchronized(obj)

code...

}

这种方式为隐式锁机制,我们不能清楚的知道它里面是如何获取锁和释放锁的。

Lock.lock

Public void run()

{

Try

{

Lock.lock();获取锁

Code..

}

Finally这里也是finally的用法的体现,一定要执行的代码,常常用于关闭资源

{

Lock.unlock();释放锁,

}

}

实现代码:

import java.util.concurrent.locks.*;

class Resource

{

      private String name;//定义商品的名称

      private int count;//定义计数器用来对商品进行记录

      private boolean flag;//定义一个标记,用来控制多线程之间的状态转换。

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

      private Condition con1 = lock.newCondition();//一组监视器监视生产者

      private Condition con2 = lock.newCondition();//一组监视器监视生产者

      public  void set(String name)//

       {

             lock.lock();//获取锁 .

             try

             {

                   while(flag)//判断获取了执行的权的线程是否满足要求,如果为false则不用捕获异常。直接生产产品,如果为真,值捕获异常,等待

                   try{con1.await();}catch(Exception e){}//  (活)  t1 (活)t0

                   this.name = name+count;    //将生产的产品的名称和记录的数目赋值给name

                   count++;//生产的产品数自加

 

                   System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产者 商品0 生产者 商品1商品2

获取生产者生产的商品的名称以及数值。

                    flag= true;//执行完打印之后通过flag标记赋值来改变线程的状态。

                   con2.signal();//用到了新特性中的特点。Condition中的方法signal唤醒功能,当前面加上对应的控制比较时,这样就可以唤醒对方中的线程。也就是唤醒了消费者中的线程。这样做的能提高效率,避免了上面那种方法中唤醒的如果是本方法中的线程对象。降低效率。

             }

             finally

             {

                   lock.unlock();//释放锁。

             }

            

       }

      public  void out()//

       {

             lock.lock();

             try

             {

                   while(!flag)

                   try{con2.await();}catch(Exception e){}//t2 t3

                   System.out.println(Thread.currentThread().getName()+"......消费者......."+this.name);//消费 商品0

                    flag= false;

                   con1.signal();//唤醒生产者的线程、

             }

             finally

             {

                   lock.unlock();

             }

       }

}

class Producer implements Runnable

{

      private Resource r;

      Producer(Resource r)

       {

             this.r = r;

       }

       publicvoid run()

       {

             while(true)

             {

                   r.set("商品");

             }

       }

}

class Consumer implements Runnable

{

       privateResource r;

      Consumer(Resource r)

       {

             this.r = r;

       }

       publicvoid run()

       {

             while(true)

             {

                   r.out();

             }

       }

}

class ProConDemo2

{

       publicstatic 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();

 

       }

}

总结:condition替代了Object类中监视器方法wait notify,notifyAll,将监视器方法单独封装成了condition对象。而且一个锁上可以组合多组监视器对象,实现了多生产者多消费时,。本方只唤醒对象中一个的操作,提高了效率。

 

原创粉丝点击