java线程安全之synchronized

本篇文章转载自时间断崖
synchronized是java中解决并发问题的一种最简单最经常使用的方法,他能够确保线程互斥的访问同步代码html

synchronized的三种应用方式

同步代码块: 锁是括号里面的对象,对给定对象加锁,进入同步代码以前要得到给定对象的锁 同步普通方法: 锁是当前实例对象,进入同步代码以前要得到当前实例的锁 同步静态方法: 锁是当前类的class对象,进入同步代码以前要得到当前类对象的锁java

举个卖火车票的例子

不使用synchronized关键字的时候会发生什么并发

public class Ticket implements Runnable{
    private int tickets = 10;//定义变量tickets,并赋值10

    public void run() {
        while (true) {
            saleTicket();
            if (tickets <= 0) {
                break;
            }
        }
    }
    public   void saleTicket () {
        if (tickets > 0) {
            try {
                Thread.sleep(10); //通过的线程休眠 10秒
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
        }
    }
}
结果:
线程二---卖出的票10
线程一---卖出的票9
线程四---卖出的票8
线程三---卖出的票8
线程二---卖出的票7
线程一---卖出的票6
线程三---卖出的票5
线程四---卖出的票4
线程二---卖出的票2
线程一---卖出的票3
线程四---卖出的票1
线程三---卖出的票1
线程一---卖出的票0
线程二---卖出的票-1

能够看到卖出了0和-1张票,还卖了好几张1,在代码逻辑中当卖到0张的时候就中止卖票了。测试

  1. 同步代码块
public class Ticket implements Runnable{
    private int tickets = 10;//定义变量tickets,并赋值10
    Object lock = new Object();//定义任意一个对象,用做同步代码的锁
    public void run() {
        while (true) {
            synchronized (lock) { //定义同步代码块
                try {
                    Thread.sleep(10); //通过的线程休眠 10秒
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
                }else {//若是tickets小于0,跳出循环
                    break;
                }
            }
        }
    }
}
  1. 同步普通方法
public class Ticket implements Runnable{
    private int tickets = 10;//定义变量tickets,并赋值10

    public void run() {
        while (true) {
            saleTicket();
            if (tickets <= 0) {
                break;
            }
        }
    }
    public synchronized void saleTicket () {
        if (tickets > 0) {
            try {
                Thread.sleep(10); //通过的线程休眠 10秒
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
        }
    }
}
  1. 同步静态方法
public class Ticket implements Runnable{
    private static int tickets = 10;//定义变量tickets,并赋值10

    public void run() {
        while (true) {
            saleTicket();
            if (tickets <= 0) {
                break;
            }
        }
    }
    public static synchronized void saleTicket () {
        if (tickets > 0) {
            try {
                Thread.sleep(10); //通过的线程休眠 10秒
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
        }
    }
}
  1. 测试代码
public class TestTicket{
    public static void main(String[] args) {
        Ticket ticket = new Ticket();//建立ticket对象
        //建立4个线程
        new Thread(ticket,"线程一").start();
        new Thread(ticket,"线程二").start();
        new Thread(ticket,"线程三").start();
        new Thread(ticket,"线程四").start();

    }
}

测试结果:线程

线程一---卖出的票10
线程一---卖出的票9
线程四---卖出的票8
线程四---卖出的票7
线程四---卖出的票6
线程四---卖出的票5
线程四---卖出的票4
线程四---卖出的票3
线程四---卖出的票2
线程四---卖出的票1

能够看到卖票结果没有超出预期code

相关文章
相关标签/搜索