1.多线程-线程安全问题演示


    多个线程对象运行同一个线程任务代码的时候,一个线程运行到判断语句后被临时阻塞了,下个线程继续判断,直接输出结果,前一个线程再输出的结果,可能会出问题

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();
        //多个线程对象调用同一个线程任务
    }
}

wKioL1c1vpzxD5V0AABKTWeUfN4468.png

2.多线程-线程安全问题原因

原因:

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

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

 

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

    导致到了数据的错误.

 

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

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


3.多线程-线程安全问题-同步代码块解决

解决:

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

 

如何代码体现呢?

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

 

格式:

synchronized(对象) //该对象是任意的
{
    //需要被同步的代码;
}


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

4.多线程-线程安全问题-同步代码块好处&弊端&前提

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

    同步弊端:降低了效率。

     

    同步的前提:

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

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

     

     synchronized(new Object()){

        }

    意思是让每个线程进到同步代码块中,就会换一把新锁。有安全隐患,没有保障多线程直接使用用一把锁。


5.多线程-线程安全问题-同步函数使用的锁

    

同步的第二种表现形式:同步函数。


问题:同步函数使用的锁是什么呢?

    同步函数使用的锁,应该是this


同步函数和同步代码块的区别?

    同步函数使用的固定锁this

    同步代码块使用的锁是可以指定的。

class Ticket implements Runnable{
    private int num = 100;
    boolean flag = true;
    Object obj = new Object();
    public void run(){
        if(flag){
            while(true){
                synchronized(this){
                    if(num>0){
                        try{Thread.sleep(10);}catch(InterruptedException e){}
                        System.out.println(Thread.currentThread().getName()+"..obj:"+num--);
                     }
                }
            }
        }else{
            while(true){
                this.sale();
            }
        }
    }
     
    public synchronized void sale(){//同步函数。
        if(num>0){
            try{Thread.sleep(10);}catch(InterruptedException e){}
            System.out.println(Thread.currentThread().getName()+"..func:"+num--);
        }
    }
}

class ThreadDemo5_Ticket_SynFunction{
    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();
    }
}


6.多线程-线程安全问题-静态同步函数使用的锁

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

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

class Ticket implements Runnable{
    private static  int num = 100;
    boolean flag = true;
    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);
        t1.start();
        try{Thread.sleep(10);}catch(InterruptedException e){}
        t.flag = false;
        t2.start();
    }
}


7.多线程-线程安全问题-单例懒汉式多线程问题

//饿汉式,不会出现线程安全问题,没有多条共享数据
class Single1{
    private static final Single1 s = new Single1();
    private Single1(){}
    public static Single1 getInstance(){
        return s;
    }
}
 
 
 
//懒汉式
 
/*
加同步关键字,解决的是安全问题。
public static  Single getInstance() {if(s==null)  {s = new Single();} }
加双重判断,是为了提高效率,不用每次都进入同步代码块。 
*/
class Single2{
    private static Single2 s = null;
    private Single2(){}
    public static  Single2 getInstance(){
        //当存在对象时,执行到第一个if语句判断条件不符合后,不用进入下面的同步代码块
        if(s==null){    
            synchronized(Single.class){
                if(s==null){
                    s = new Single();
                }
            }
        }
        return s;
    }
}

 

 

14-多线程-线程安全问题-死锁示例

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