你不知道的Java学习笔记24-- 线程同步

线程同步

1、线程同步就是多个线程并发地访问同一个数据。
2、多线程就是同时去做同样的事情,目的是提高程序的运行效率。

通过“售票”模拟线程同步

/*
 * 通过"卖票"模拟线程同步
 */
public class    TestTicket {
    public static void main(String[] args) {
        //创建实现类
        SaleTicket st=new SaleTicket();
        //创建线程对象去调用实现类
        Thread t1=new Thread(st);
        Thread t2=new Thread(st);
        Thread t3=new Thread(st);
        //设置线程名称
        t1.setName("售票员1");
        t2.setName("售票员2");
        t3.setName("售票员3");
        //调用start()方法激活线程
        t1.start();
        t2.start();
        t3.start();

    }

}
//定义SaleTicket去实现Runnable接口
class SaleTicket implements Runnable{
    //定义ticket常量
    int ticket=50;
    //重写run()方法
    public void run() {
        while(true)
        {
            if(ticket>0)
            {
                try {
                    Thread.currentThread();
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":\t"+ticket--);
            }
            else{
                break;
            }
        }



    }

}

这里写图片描述

但是线程共同访问同一数据(线程并发)出现资源访问错误也叫线程安全问题,即打印不合理的数据0票、-1票、同一个票号被打印两次。因为售票员3和售票员2在ticket>0为true时进入if循环,当时处于休眠状态。在售票员3和售票员2休眠的时候由于售票员1打印ticket,此时的ticket=0。但是售票员3和售票员2休眠已经在if循环体里面了,循环的条件ticket>0对他们两个来说不起作用。所以售票员3和售票员2也顺利打印ticket,但是打印的是不合法的数据,因此导致0票和-1票的出现。

同步锁*重点内容*

使用同步锁可以解决线程共同访问同一数据(线程并发)出现资源访问错误的问题/线程安全性问题。
同步锁相当于厕所的门,锁定已经占有的资源,直到用完后才释放资源,别人才可以使用此资源。

同步锁分为同步代码块和同步方法两种。
(一)同步代码块

/*
 * 通过"卖票"模拟线程同步
 */
public class    TestTicket {
    public static void main(String[] args) {
        //创建实现类
        SaleTicket st=new SaleTicket();
        //创建线程对象去调用实现类
        Thread t1=new Thread(st);
        Thread t2=new Thread(st);
        Thread t3=new Thread(st);
        //设置线程名称
        t1.setName("售票员1");
        t2.setName("售票员2");
        t3.setName("售票员3");
        //调用start()方法激活线程
        t1.start();
        t2.start();
        t3.start();

    }

}
//定义SaleTicket去实现Runnable接口
class SaleTicket implements Runnable{
    //定义ticket常量
    int ticket=50;
    //定义一个lock常量
    String lock="Lock";
    //重写run()方法
    public void run() {
        while(true)
        {
            //同步代码块
            synchronized(lock){
                if(ticket>0)
                {
                    try {
                        Thread.currentThread();
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":\t"+ticket--);
                }
                else{
                    break;
                }
            }

        }   
    }
}

这里写图片描述

(二)同步方法

/*
 * 通过"卖票"模拟线程同步并采用同方法 解决线程安全性问题
 */
public class TestTicket {
    public static void main(String[] args) {
        //创建实现类
        SaleTicket st=new SaleTicket();
        //创建线程对象去调用实现类
        Thread t1=new Thread(st);
        Thread t2=new Thread(st);
        Thread t3=new Thread(st);
        //设置线程名称
        t1.setName("售票员1");
        t2.setName("售票员2");
        t3.setName("售票员3");
        //调用start()方法激活线程
        t1.start();
        t2.start();
        t3.start();

    }

}
//定义SaleTicket去实现Runnable接口
class SaleTicket implements Runnable{
    //定义ticket常量
    int ticket=50;
    //重写run()方法
    public void run() {
        //一直执行调用sale()方法,直到sale()为false时跳出循环
        while(true)
        {
            if(!sale())
            {
                break;
            }

        }
    }
    //同步方法
    public synchronized boolean sale()
    {
        if(ticket>0)
        {
            try {
                Thread.currentThread();
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":\t"+ticket--);
        }
        else{
            return false;
        }
        return true;
    }

}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/lin434406218/article/details/52742313
今日推荐