一, 解决线程安全总体可分为两大类:
1. 使用 synchronized 关键字 (可修饰代码块或方法)
(1) 使用 synchronized 关键字修饰代码块
- public class ThreadDemo {
- public static void main(String[] args) {
- ThreadSafe1 thread = new ThreadSafe1();
- Thread t1 = new Thread(thread);
- Thread t2 = new Thread(thread);
- Thread t3 = new Thread(thread);
- t1.setName("窗口一");
- t2.setName("窗口二");
- t3.setName("窗口三");
- t1.start();
- t2.start();
- t3.start();
- }
- }
- class ThreadSafe1 implements Runnable{
- // 定义车票的数量
- private int ticket = 100;
- @Override
- public void run() {
- while(true) {
- synchronized(ThreadSafe1.class) { // 同步监视器为 ThreadSafe1.class, 它只加载一次, 是唯一的, 该同步代码块里包含着共享数据的操作
- if(ticket> 0) {
- System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票");
- // 车票数量减一
- ticket--;
- }else {
- break;
- }
- }
- }
- }
- }
(2) 使用 synchronized 关键字修饰方法
- public class ThreadDemo {
- public static void main(String[] args) {
- ThreadSafe2 thread = new ThreadSafe2();
- Thread t1 = new Thread(thread);
- Thread t2 = new Thread(thread);
- Thread t3 = new Thread(thread);
- t1.setName("窗口一");
- t2.setName("窗口二");
- t3.setName("窗口三");
- t1.start();
- t2.start();
- t3.start();
- }
- }
- class ThreadSafe2 implements Runnable{
- // 定义车票的数量
- private int ticket = 100;
- @Override
- public void run() {
- while(true) {
- // 调用窗口售票方法
- sale();
- if(ticket == 0) {
- break;
- }
- }
- }
- // 实现窗口售票
- public synchronized void sale() { // 该方法的同步监视器为 ThreadSafe2 的对象, 它是唯一的, 这里面也存放着对共享数据的操作
- if(ticket> 0) {
- System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票");
- // 车票数量减一
- ticket--;
- }
- }
- }
2. 使用 Lock 锁方式解决线程安全问题
- public class ThreadDemo {
- public static void main(String[] args) {
- ThreadSafe3 thread = new ThreadSafe3();
- Thread t1 = new Thread(thread);
- Thread t2 = new Thread(thread);
- Thread t3 = new Thread(thread);
- t1.setName("窗口一");
- t2.setName("窗口二");
- t3.setName("窗口三");
- t1.start();
- t2.start();
- t3.start();
- }
- }
- class ThreadSafe3 implements Runnable{
- // 定义车票的数量
- private int ticket = 100;
- private ReentrantLock lock = new ReentrantLock();
- @Override
- public void run() {
- while(true) {
- try {
- lock.lock(); // 对对操作共享数据的代码进行加锁
- // 进行线程休眠, 增加其他线程调用的机会
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if(ticket> 0) {
- System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票");
- // 车票数量减一
- ticket--;
- }else {
- break;
- }
- }finally {
- lock.unlock(); // 进行解锁
- }
- }
- }
- }
二, synchronized 关键字与 Lock 锁方式的区别
(1) 两者都可以解决线程安全问题
(2)synchronized 关键字既可以修饰代码块又可以修饰方法; 而 Lock 锁方式只可以修饰代码块
(3)synchronied 关键字修饰的代码块或方法在运行结束后, 会自动释放锁; 而 Lock 锁方式需手动为代码块加锁并释放锁
(4) 从性能上, Lock 锁方式优于 synchronized 关键字
来源: http://www.bubuko.com/infodetail-3112771.html