Java之线程安全

1.线程安全问题:

需求:模拟火车票100张 售票窗口
分析:
      1.售票窗口使用线程来模拟
      2.开4个窗口同时卖100张票
      3.4个窗口卖票的任务是一样

public class MyRunnable implements Runnable {

    int tickets = 100;

    @Override
    public void run() {

        while (true){
            if (tickets < 1){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
            tickets--;
        }
    }
}




public class Tests {
    public static void main(String[] args) {
        /*
        * 需求:模拟火车票100张 售票窗口
        *
        * 分析:
        *       1.售票窗口使用线程来模拟
        *       2.开4个窗口同时卖100张票
        *       3.4个窗口卖票的任务是一样
        * */
        //创建任务对象
        MyRunnable mr = new MyRunnable();

        //创建四个窗口
        Thread t1 = new Thread(mr, "窗口1");
        Thread t2 = new Thread(mr, "窗口2");
        Thread t3 = new Thread(mr, "窗口3");
        Thread t4 = new Thread(mr, "窗口4");

        // 启动线程,执行程序
        t1.start();
        t2.start();
        t3.start();
        t4.start();

       
    }
}

程序出现了几个问题
  1. 四个窗口输出了相同的票数
  2. 遗漏票
  3. 负数票

 

2.同步代码块:

synchronized 关键字
synchronized 关键字:表示【同步】的,他可以对 多行代码 进行 同步
      将多行代码当成一个完整的整体,一个线程如果进入到这个代码块中,会全部执行完毕
      执行结束后,其他线程才会执行
      这样,即可保证这多行代码昨晚完整的整体,被一个线程完整的执行完毕
synchronized 被称之为“重量级的锁”  同时呢,也被部分程序员称之为【悲观锁】 --- 效率比较低
synchronized : 有几种使用方法
      - 同步代码块【常用的】
      - 同步方法【 常用的】
使用场景:
      当我们使用多个线程访问同一个资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题
  以上,我们多线程并发访问一个资源的时候容易出现安全性问题,也就是解决重复票或遗漏票的问题,Java提供了【同步机制】synchronized来处理
同步锁:synchronized
      synchronized关键字可以用于方法中的某个区块中,表示支队这个区块的资源实行【互斥访问】
格式:
      synchronized(锁对象){
          需要同步操作的代码
      }
锁对象:
      1. 语法上,锁对象可以是任意类的对象
      2. 多条线程想要实现同步,必须锁对象一致

public class MyRunnable implements Runnable {
    //共享的变量
    int tickets = 100;
    @Override
    public void run() {

        while (true){
            // 加锁
            synchronized ("heihei") {
                if (tickets < 1) {
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":正在售出第" + tickets + "张票");
                tickets--;
            }
            // 解锁
        }
    }



public class Tests {
        public static void main(String[] args) {
            //创建任务对象
            MyRunnable mr = new MyRunnable();

            //创建四个窗口
            Thread t1 = new Thread(mr, "窗口1");
            Thread t2 = new Thread(mr, "窗口2");
            Thread t3 = new Thread(mr, "窗口3");
            Thread t4 = new Thread(mr, "窗口4");

            // 启动线程,执行程序
            t1.start();
            t2.start();
            t3.start();
            t4.start();

   
        }
}

3.同步方法:

     概述: 使用synchronized修饰的方法,叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外面等着
     格式:
         权限修饰符 synchronized 返回值类型 方法名名称(参数列表){
         }
     锁对象:
         非静态同步方法:锁对象是this
         静态同步方法: 锁对象是该方法所在类的字节码对象(类名.class)

public class MyRunnable implements Runnable {

    // 共享变量
    int ticksts = 100;

    @Override
    public void run() {

        while (true){
            if (sellTickets()) break;

        }
    }
    // synchronized修饰的就是同步方法  【非静态同步方法】
    private synchronized boolean sellTickets() {
        if (ticksts < 1){
            return true;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"正在出售第"+ticksts+"张票");
        ticksts--;
        return false;
    }
}





public class Tests {
    public static void main(String[] args) {

        //创建任务对象
        MyRunnable mr = new MyRunnable();


        //创建四个窗口
        Thread t1 = new Thread(mr, "窗口1");
        Thread t2 = new Thread(mr, "窗口2");
        Thread t3 = new Thread(mr, "窗口3");
        Thread t4 = new Thread(mr, "窗口4");

        // 启动线程,执行程序
        t1.start();
        t2.start();
        t3.start();
        t4.start();


    }
}

4.同步方法的锁对象

在日常开发中,一条线程使用的是同步代码块,一条线程使用的是同步方法,但这两条线程需要同步的相关业务
  实现这个学术,同步代码块和同步方法的锁对象就必须一致
  而同步方法的锁对象是默认的,所以必须清楚同步方法的锁对象
同步锁是谁?
      对与非static方法,锁对象就是this
      对于static方法,我们使用当前方法所在类的字节码对象(类名.class)

public class Demo {

    public synchronized void method(){
        System.out.println(Thread.currentThread().getName()+"打开厕所门");
        System.out.println(Thread.currentThread().getName()+"关闭厕所门");

        // 线程休眠一会儿  表示  ing...
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"开门洗手走人");
    }
}





public class Tests {
    public static void main(String[] args) {

        Demo demo = new Demo();

        //张三上厕所
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.method();
            }
        },"张三").start();

        //李四上厕所
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.method();
            }
        },"李四").start();
    }
}

5.Lock锁

java.util.concurrent.locks.Lock 接口
      Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作
          同步代码块和同步方法具有的功能 Lock都有,除此之外,更加强大,更加面向对象
Lock锁 也称之为 同步锁。加锁和释放锁
      - public void lock()  加同步锁
      - public void unlock()  释放锁

public class MyRunnable implements Runnable{
    //共享的变量
    int tickets = 100;
    Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true) {

            // 加锁
            lock.lock();
            if (tickets < 1){

                lock.unlock();
                break;
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
            tickets--;

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




public class Tests {
    public static void main(String[] args) {

        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr,"窗口1");
        Thread t2 = new Thread(mr,"窗口2");
        Thread t3 = new Thread(mr,"窗口3");
        Thread t4 = new Thread(mr,"窗口4");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        System.out.println("程序结束");

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值