JavaSE-多线程-第二讲

静态同步函数

同步锁是谁?
对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。

面试问:静态同步函数锁是哪一个?
静态方法中根本无this ,此时同步代码块中使用 sychronized(this) 与 public static void show() 使用的锁是不一样的。静态同步函数使用的同步锁是当前类的字节码对象。类进栈的时候,java 类进内存会创建字节码对象(当前class 文件所属对象).
获取字节码对象的方法:
/*** 或取类字节码对象的两种方法:

  •   class getClass class thread.Ticket
    
  •    Class  clazz class thread.Ticket
    

*/
System.out.println(" class getClass "+ticket.getClass());
Class clazz= Ticket.class;
System.out.println(" Class clazz "+clazz);

package thread;
class   Ticket    implements    Runnable{
    private  static    int  num =100;
    boolean  flag=true;
  //  Object  object =new Object();
    @Override
    public    void run() {
        if(flag==true){
            while (true){
               synchronized (this.getClass()){//当前类的字节码对象
                   if(num>0){
                       try{
                        Thread.sleep(100);
                       }catch (InterruptedException  e){
                           e.printStackTrace();
                       }
                       System.out.println(" thread  name"+Thread.currentThread()   +"obj ="+num--);
                   }
               }
            }
        }else{
           while (true){
               this.show();
           }
        }
    }
    //封装函数
    public     static   synchronized   int   show(){
        if(num>0){
            try{
                Thread.sleep(10);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(" thread  name"+Thread.currentThread()   +"num ="+num--);
        }
        if(num==0){
            return  1;
        }
        return   0;
    }
}
public class SynFunctionLockDemo {
    public static void main(String[] args) {
        Ticket   ticket  =new Ticket();
        /***  或取类字节码对象的两种方法:
         * class getClass class thread.Ticket
         *        Class  clazz class thread.Ticket
         */
        System.out.println(" class getClass "+ticket.getClass());
        Class  clazz= Ticket.class;
        System.out.println("       Class  clazz "+clazz);
        Thread   thread1  =new Thread(ticket);
        Thread  thread2 =new Thread(ticket);
       /* thread1.start();
        try{
            Thread.sleep(100);
        }catch (InterruptedException  e){
            e.printStackTrace();
        }
        ticket.flag=false;
        thread2.start();*/
    }
}

单例模式涉及的多线程问题

// 饿汉式—延迟加载模式 (技术细节,面试时候都面这一个!)
// 1. 有共享数据 sinlge 对象
// 2. 有多条语句操作共享数据? getsIngton()有 多条语句
//解决方法:1.同步函数 加同步但是每次都要synchronized 判断锁 执行效率降低。
//同步代码块:
// 此时多加一层 if(single== null )
class Sinlge {
private static Sinlge sinlge;
private SIngton(){
}
/* 方法 1; 同步函数 但是效率低
public static synchronized Sinlge getsIngton(){ //多条语句有安全隐患
if(sinlge==null){
// 执行过程中 线程0 线程1都会进入这里 可能都 new 对象
sinlge =new Sinlge();
}
return sinlge;
}*/
// 同步代码块 1.加第一层判断是为了提高效率
线程0 获得锁,此时 single 还是null 线程1再进入判断 sychronized

public static     Sinlge   getsIngton(){ //多条语句有安全隐患
    **if(sinlge==null){**
        synchronized (Sinlge.class){
            // 线程0  线程1 可能都 new  对象
            **if(sinlge==null){**
                sinlge =new Sinlge();
            }
        }
    }
    return   sinlge;
}

}
//懒汉式-- 不存在安全问题
// 1. 有共享数据 sinlge 对象
// 2. 有多条语句操作共享数据? getsIngton()只有一条语句
class Single2 {
private static final Single2 single =new Single2();
private Single2(){

}
public static Single2 getInstance(){
return single;
}
}

多线程死锁

面试请写出一个死锁程序?

原则:死锁:常见情景之一:同步的嵌套。
package thread;

class TicketDemo implements Runnable{
private boolean flag;
private int num=100;
TicketDemo (boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
synchronized (MyLock.myLock1){
System.out.println(" lock a"+Thread.currentThread().getName());
synchronized (MyLock.myLock2){

               System.out.println("   flag= true"+Thread.currentThread()+" num"+num--);
           }

       }

   }else {
       synchronized (MyLock.myLock2){
           System.out.println("   lock b"+Thread.currentThread().getName());
           synchronized (MyLock.myLock1){

               System.out.println("   flag= flase"+Thread.currentThread()+" num"+num--);
           }

       }


   }
}

}
class MyLock{

public   static   MyLock   myLock1= new MyLock();
public   static   MyLock   myLock2 =new MyLock();

}

public class DeathLock {

public static void main(String[] args) {
       TicketDemo  ticketDemo  =new TicketDemo(true);
       TicketDemo  ticketDemo1 =new TicketDemo(false);

       Thread  thread =new Thread(ticketDemo);
       Thread  thread1 =new Thread(ticketDemo1);
       thread.start();
       thread1.start();
}

}
输出 lock aThread-0
lock bThread-1:
此时 线程0获得 locka 但是没有获得lockb 线程 1 获得lockb 没有获得 locka

什么时候需要多线程通讯?

1.多个线程共享资源。2.对共享资源的处理不同。

package thread;
class   Resoure2{//资源
    public   String   name;
    public  String   sex;
}
//输入

class   InPut2 implements  Runnable{
    Resoure2  r;
    InPut2( Resoure2  r){
       this.r=r;
    }
    @Override
    public void run() {
        int x=0;
        while (true){

            synchronized (r){
               if(x==0){
                 r.name="wwwww";
                 r.sex=" man ";
               }else {
                   r.name="qqq";
                   r.sex="women";
                   System.out.println("   中文  women ----------------------------");
               }
            }
            x=(x+1)%2; // 1   0   1   0
            System.out.println("22222222222222 x=" +x);
        }

    }
}
//输出



class   OutPut2   implements   Runnable{
    Resoure2  r;

    OutPut2(Resoure2  r){
        this.r=r;
    }
    @Override
    public void run() {
        while (true){
            synchronized (r){

                try{

                    Thread.sleep(1000);
                }catch ( InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("   out name  "+r.name+ "sex"+r.sex);
            }

        }
    }
}
public class ResoureDemo {
    public static void main(String[] args) {
        Resoure2  r= new Resoure2();
        InPut2  inPut =new InPut2(r);
        OutPut2 outPut =new OutPut2(r);
        Thread  thread1= new Thread(inPut);
        Thread  thread2= new Thread(outPut);
        thread1.start();
        thread2.start();
    }
}

什么是等待唤醒机制?

使用到的方法:
1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
2,notify():唤醒线程池中一个线程(任意).
3,notifyAll():唤醒线程池中的所有线程。
这些方法都必须定义在同步中 也就是sychronized{ }内。
因为这些方法是用于操作线程状态的方法。
必须要明确到底操作的是哪个锁上的线程。例如:下例中 r.wait() r.notify() 直接调用会出现:java.lang.IllegalMonitorStateException

问题:为什么操作线程的方法wait notify notifyAll定义在了Object类中?

因为这些方法是监视器的方法。监视器其实就是锁 例如: Resource r。
锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。

唤醒机制原理解释:

在这里插入图片描述
1.input 获得锁 设置name =mike sex =nan
表示赋值成功,input 还有执行权,又会赋值此时name="丽丽"可能会赋值多次,无限循环。 flag=true 表示已经赋值,应该output 输出但是执行权还在input,这个时候flag=true要让 input 停一下. 加入判断:
if(flag){
r.wait();
}
等到output 执行完在唤醒。
如果 output 获得执行权:flag==flase 也要处于冻结状态。

//资源
class Resource
{
  private   String name;
  private   String sex;
    
    public   boolean  flag= false;
}
//输入
class Input implements Runnable
{
    Resource r ;
    // Object obj = new Object();
    Input(Resource r)
    {
        this.r = r;
    }
    public void run()
    {
        int x = 0;
        while(true)
        {
            System.out.println(" input 1");
            synchronized(r)
            {
                if(r.flag){
                    System.out.println(" input --wait");
                    try{  r.wait();}catch ( InterruptedException  e){ e.printStackTrace();}
                }

                System.out.println(" input2-- synchronized-beign");
                if(x==0)
                {
                    r.name = "小王";
                    r.sex = "男";
                }
                else
                {
                    r.name = "丽丽";
                    r.sex = "女";
                }
                System.out.println(" input2-- synchronized-end");
                r.notify();
                r.flag=true;
            }

            x = (x+1)%2;
System.out.println(" input退出锁  x="+x);
        }
    }
}
//输出
class Output implements Runnable
{

    Resource r;
    // Object obj = new Object();
    Output(Resource r)
    {
        this.r = r;
    }

    public void run()
    {
        while(true)
        {
            System.out.println(" output1");
            synchronized(r)
            {
                if(!r.flag){
                    System.out.println(" out --wait");
                    try{  r.wait();}catch ( InterruptedException  e){ e.printStackTrace();}
                }
                System.out.println(" output2- synchronized-begin");
                System.out.println(" output2");
                System.out.println(r.name+"....."+r.sex);
                System.out.println(" output2- synchronized-end");
                r.notify();
                r.flag=false;
            }
            System.out.println(" output退出锁");
        }
    }
}

public class ResourceDemo {

    public static void main(String[] args)
    {
        System.out.println(" bengin ----");
        //创建资源。
        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();
    }



执行结果:
bengin ----
input 1
input2-- synchronized-beign
output1
input2-- synchronized-end
output2- synchronized-begin
output2
input退出锁 x=1
input 1
小王…男
output2- synchronized-end
output退出锁
output1
out --wait
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
input退出锁 x=0
input 1
丽丽…女
output2- synchronized-end
output退出锁
output1
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
小王…男
output2- synchronized-end
input退出锁 x=1
input 1
input2-- synchronized-beign
input2-- synchronized-end
output退出锁
output1
output2- synchronized-begin
output2
丽丽…女
output2- synchronized-end
output退出锁
output1
out --wait
input退出锁 x=0
input 1
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
input退出锁 x=1
input 1
小王…男
output2- synchronized-end
output退出锁
output1
input2-- synchronized-beign
input2-- synchronized-end
output2- synchronized-begin
output2
丽丽…女
output2- synchronized-end
output退出锁
output1
out --wait

多线程唤醒机制优化

使用同步函数代替同步代码块做封装
name 和sex 设置成私有, 同步函数 set ,out ;


//代码优化 ----等待唤醒机制
//资源
class Resource3
{
  private   String name;
  private    String sex;

  public   boolean  flag= false;
    //使用同步函数
    public  synchronized   void  set( String name,String sex){

        if(flag){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }

        }
        this.name =name;
        this.sex=sex;
        this.flag=true;//表示有值了
        this.notify();//唤醒 out

    }

    public   synchronized  void  out(){
        if(!flag){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println(" name "+this.name+" sex "+this.sex);
        this.flag=false;
        this.notify();
    }
}
//输入
class Input3 implements Runnable
{
    Resource3 r ;
    // Object obj = new Object();
    Input3(Resource3 r)
    {
        this.r = r;
    }


    public void run()
    {
        int x = 0;
        while(true)
        {
                if(x==0)
                {

                    r.set("小王","男");
                }
                else
                {
                    r.set("丽丽","女");
                }
               // System.out.println(" input2-- synchronized-end");
            x = (x+1)%2;
            }
        }

}
//输出
class Output3 implements Runnable
{

    Resource3 r;
    // Object obj = new Object();
    Output3(Resource3 r)
    {
        this.r = r;
    }

    public void run()
    {
        while(true)
        {
         //   System.out.println(" output1");

               r.out();
        }
    }
}

public class ResourceDemo3 {

    public static void main(String[] args)
    {
        System.out.println(" bengin ----");
        //创建资源。
        Resource3 r = new Resource3();
        //创建任务。
        Input3 in = new Input3(r);
        Output3 out = new Output3(r);
        //创建线程,执行路径。
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        //开启线程
        t1.start();
        t2.start();
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值