线程安全

Thread类:

    

 

  当new Thread()时,线程处于新建状态,当start()时,线程处于运行状态,并且CPU没空时,处于受阻塞状态,当CPU有空时,有处于运行状态,当stop()时或run()结束时,线程处于死亡状态,同时,

当运行时,调用wait()方法,线程处于等待状态,在调用notify()方法,又处于运行状态,如果CPU被抢走,则处于被阻塞状态,当调用sleep()方法,线程处于休眠状态,时间到了之后,又处于运行状态,如果CPU被抢走,又处于被阻塞状态。

线程安全问题:

      

public class Tickets implements Runnable{
    //100张票
    //多线程共享数据容易出现安全问题
private int t=100;
public void run() {
    //循环卖票
    while(true){
        if(t>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread()
                    .getName()+"卖了第:"+t--+"张票");
        }
    }
}
}
public class Demo01 {

    public static void main(String[] args) {
        //创建线程任务
        Tickets t=new Tickets();
        //创建三个线程对象
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        Thread t3=new Thread(t);
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }

}

首先100张票必须三条线程同时卖,所以100张票要定义在成员变量中,当只有一张票时,t1>0,t1进入程序,t1开始等着,t2>0,满足条件,t2进入,t2开始等着,t3>0,满足条件,t3进入,t3等着,t1开始执行,卖第一张票,t2执行,卖0张票,t3卖-1张票。

总结:当有多个线程共享一个资源时,会出现线程安全问题.

第一种解决方式:

      

同步代码块:

      

public class Tickets02 implements Runnable{
    //100张票
    //多线程共享数据容易出现安全问题
private int t=100;
private Object obj=new Object();
public void run() {
    //循环卖票
    while(true){
        //同步代码块
        synchronized (obj) {
            if(t>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread()
                        .getName()+"卖了第:"+t--+"张票");
            }
        }
    
    }
}
}

第二种方式:

  同步方法:

      

public class Tickets03 implements Runnable{
    //100张票
    //多线程共享数据容易出现安全问题
private int t=100;
public void run() {
    //循环卖票
    while(true){
    sale();
    }
}
//写一个同步方法
public synchronized void sale(){
    if(t>0){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread()
                .getName()+"卖了第:"+t--+"张票");
    }
}
}

第三种方式:lock接口

      

 

     

public class Tickets04 implements Runnable{
    //100张票
    //多线程共享数据容易出现安全问题
private int t=100;
//创建lock锁对象
private Lock lock=new ReentrantLock();
public void run() {
    //循环卖票
    while(true){
        //获得锁
        lock.lock();
        if(t>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread()
                    .getName()+"卖了第:"+t--+"张票");
        }
        //释放锁
        lock.unlock();
    }
}
}

 StringBuffer与StringBuilder:

            StringBuffer安全,但速度慢。

            StringBuilder快,但相对来说不安全。

            因为StringBuffer中的方法都用了synchronized。

 public synchronized int capacity() {
        return value.length;
    }


    @Override
    public synchronized void ensureCapacity(int minimumCapacity) {
        super.ensureCapacity(minimumCapacity);
    }

    /**
     * @since      1.5
     */
    @Override
    public synchronized void trimToSize() {
        super.trimToSize();
    }

 

posted @ 2020-11-06 09:58  马雪峰1  阅读(99)  评论(0编辑  收藏  举报