线程安全

2021-04-13  本文已影响0人  Amy木婉清

线程安全问题出现的根本原因和解决方案:

线程安全问题出现的根本原因:

1.必须要存在两个或者两个以上的线程共享着一个资源
2.操作共享资源的代码必须有两句或者两句以上
解决思路:
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的。
必须要当前线程把这些代码都执行完毕后,其他线程才能运算。
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁。

解决方案: 1.同步函数 2.同步代码块
1.同步代码块
 synchronized(锁){
            需要被同步的代码
        }
class SaleTicket extends Thread{
     static int num = 50;//票数  非静态的成员变量,非静态的成员变量数据是在每个对象中都会维护一份数据的。
     public SaleTicket(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        while(true){
            //同步代码块
            synchronized ("锁") {                
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+"售出了第"+num+"号票");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    num--;
                }else{
                    System.out.println("售罄了..");
                    break;
                }
            }           
        }
    }           
} 
public class Demo4 {    
    public static void main(String[] args) {
        //创建三个线程对象,模拟三个窗口
        SaleTicket thread1 = new SaleTicket("窗口1");
        SaleTicket thread2 = new SaleTicket("窗口2");
        SaleTicket thread3 = new SaleTicket("窗口3");
        //开启线程售票
        thread1.start();
        thread2.start();
        thread3.start();        
    }   
}
注意:

1.同步代码块的锁可以是任意对象.同步函数的锁是固定的,非静态函数的锁是this对象.静态函数的锁是class对象。
2.锁对象必须是多线程共享的对象,否则锁不住。
3.在同步代码块或是同步函数中用sleep的方法是不会释放锁对象的,如果是调用了wait方法是会释放对象的。

2.同步函数
   修饰符 synchronized 返回值类型   函数名(形参列表..){

        }
class BankThread extends Thread{
    static int count = 5000;
    public BankThread(String name){
        super(name);
    }
    
    @Override  //
    public synchronized  void run() {
        while(true){
            synchronized ("锁") {                
                if(count>0){
                    System.out.println(Thread.currentThread().getName()+"取走了1000块,还剩余"+(count-1000)+"元");
                    count= count - 1000;
                }else{
                    System.out.println("取光了...");
                    break;
                }
            }
        }
    }
 
public class Demo1 {
 
    public static void main(String[] args) {
        //创建两个线程对象
        BankThread thread1 = new BankThread("老公");
        BankThread thread2 = new BankThread("老婆");
        //调用start方法开启线程取钱
        thread1.start();
        thread2.start();    
    }
    
}
同步函数注意的事项:

1.如果函数是一个非静态的同步函数,那么锁对象是this对象;
2.如果韩式是静态的同步函数,那么锁对象是当前函数所属的类的字节码文件(class对象);
3.同步函数的锁对象是固定的,不能由自己指定。

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

同步函数的锁是固定的this;
同步代码块的锁是任意的对象。
建议使用同步代码块。
静态的同步函数使用的锁是该函数所属字节码文件对象
可以用getClass()方法来获取,也可以使用当前类名.class表示。

上一篇下一篇

猜你喜欢

热点阅读