昆仑山:眼中无形心中有穴之穴人合一

夫君子之行,静以修身,俭以养德;非澹泊无以明志,非宁静无以致远。夫学须静也,才须学也;非学无以广才,非志无以成学。怠慢则不能励精,险躁则不能冶性。年与时驰,意与岁去,遂成枯落,多不接世。悲守穷庐,将复何及!

 

java多线程艺术:线程同步

问题引出

/*
* 实现买票案例
* */
public class RunnableImpl implements Runnable{
    //定义一个多线程共享的票源
    private int ticket=100;

    // 设置线程任务:买票
    @Override
    public void run() {
        /**
        //  单线程模式 卖票方式

        //先判断票是否存在
        if(ticket>10){
            //票存在,买票ticket
            System.out.println(Thread.currentThread().getName()+"正在卖第----->"+ticket+"张票");
            ticket--;

        }
         */

        // 多线程卖票方式

        //使用死循环,让卖票操作重复执行

        while (true){
            //先判断票是否存在
            if(ticket>10){
                // 提高安全问题出现的概率  让程序睡眠
                // try...catch...  这个代码不是必须的  目的让大家看到有重复现象 说明这个卖票系统存在不合理

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


                //票存在,买票ticket
                System.out.println(Thread.currentThread().getName()+"正在卖第----->"+ticket+"张票");
                ticket--;

            }
        }

    }
}





/*
 模拟卖票案例

 创建3个线程(相当于 三个卖票窗口)  对共享的票进行出售
 */
public class Driver {
    public static void main(String[] args) {

//        创建Runnable 接口的实现类对象
        RunnableImpl run=new RunnableImpl();

//        创建Thread类对象 构造方法中传递Runnable 接口的实现类对象
        Thread t1=new Thread(run);
        Thread t2=new Thread(run);
        Thread t3=new Thread(run);
//     调用start 方法开启多线程
        t1.start();
        t2.start();
        t3.start();
   }


}







解决不同步的手段

  1. 同步代码块
  2. 同步方法
  3. 锁机制

同步代码块


/*
 * 卖票案例出现了线程安全问题
 * 卖出了不存在的票和重复的票
 *
 *
 * 解决线程安全问题的一种方案: 使用同步代码块
 *
 * 格式:
 *  synchronized(锁对象){
 *   可能会出现线程安全问题的代码(访问了 共享数据的代码)
 * }
 *
 * 注意:
 *   1. 通过代码块中的锁对象,可以使用任意的对象
 *   2. 但是必须保证多个线程使用的锁对象是同一个
 *   3.锁对象作用: 把同步代码块锁住,只让一个线程 在同步代码块中执行
 *
 *
 * */
public class RunnableImpl implements Runnable {
    //定义一个多线程共享的票源
    private int ticket = 100;

    //创建锁对象  留一个问题思考一下  为什么 锁对象不写在 run() 方法里
    Object obj = new Object();


    // 设置线程任务:买票
    @Override
    public void run() {
        /**
         //  单线程模式 卖票方式

         //先判断票是否存在
         if(ticket>10){
         //票存在,买票ticket
         System.out.println(Thread.currentThread().getName()+"正在卖第----->"+ticket+"张票");
         ticket--;

         }
         */

        // 多线程卖票方式

        //使用死循环,让卖票操作重复执行

        while (true) {
            // 同步代码块
            synchronized (obj) {
                //先判断票是否存在
                if (ticket > 0) {
                    // 提高安全问题出现的概率  让程序睡眠
                    // try...catch...  这个代码不是必须的  目的让大家看到有重复现象 说明这个卖票系统存在不合理

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                    //票存在,买票ticket
                    System.out.println(Thread.currentThread().getName() + "正在卖第----->" + ticket + "张票");
                    ticket--;

                }
            }
        }

    }
}




同步方法

/*
 * 卖票案例出现了线程安全问题
 * 卖出了不存在的票和重复的票
 *
 *
 * 解决线程安全问题的一种方案: 使用同步方法
 *
 * 使用步骤:
 *      1. 把访问了共享数据的代码抽取出来,放到一个方法中
 *      2. 在方法上添加synchronized修饰符
 *
 * 语法格式: 定义方法的格式
 *    修饰符  synchronized 返回值类型  方法名(参数列表){
 *
 *              可能会出现线程安全问题的代码(访问了 共享数据的代码)
 *      }

 * */
public class RunnableImpl implements Runnable {
    //定义一个多线程共享的票源
    private int ticket = 100;

    //创建锁对象  留一个问题思考一下  为什么 锁对象不写在 run() 方法里
    Object obj = new Object();


    // 设置线程任务:买票
    @Override
    public void run() {
        System.out.println("this:\t"+this);
        // 多线程卖票方式
        //使用死循环,让卖票操作重复执行
        while (true) {
            payTicket();
        }
    }

    /**
     * 定义一个 同步方法
     *
     *
     *同步方法也会把方法内部的代码锁住
     *
     * 只让一个线程执行
     *
     * 同步方法的锁对象是谁?
     *  就是实现类对象 new RunnableImpl()
     * 也就是 this
     */
    public synchronized void payTicket() {

            //先判断票是否存在
            if (ticket > 0) {
                // 提高安全问题出现的概率  让程序睡眠
                // try...catch...  这个代码不是必须的  目的让大家看到有重复现象 说明这个卖票系统存在不合理

                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //票存在,买票ticket
                System.out.println(Thread.currentThread().getName() + "正在卖第----->" + ticket + "张票");
                ticket--;
            }
    }


    /**
     *  上面同步方法  还可以等价写法 如下
     *
     *
     *   public  void payTicket() {
     *
     *   synchronized (this){
     *
     *          //先判断票是否存在
     *                 if (ticket > 0) {
     *                     // 提高安全问题出现的概率  让程序睡眠
     *                     // try...catch...  这个代码不是必须的  目的让大家看到有重复现象 说明这个卖票系统存在不合理
     *
     *                     try {
     *                         Thread.sleep(10);
     *                     } catch (InterruptedException e) {
     *                         e.printStackTrace();
     *                     }
     *                     //票存在,买票ticket
     *                     System.out.println(Thread.currentThread().getName() + "正在卖第----->" + ticket + "张票");
     *                     ticket--;
     *                 }
     *
     *         }
     *
     *
     *
     *     }
     *
     *
     *
     */
}

静态同步方法

锁对象是谁?
不能是this
this 是创建对象之后产生的,静态方法优先对象

静态方法的锁对象是本类的class属性--->class 文件对象(反射)

Lock锁机制

posted on 2019-05-26 11:47  Indian_Mysore  阅读(202)  评论(0编辑  收藏  举报

导航