解决线程安全的几种方式

一、解决线程安全总体可分为两大类:

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关键字

原文地址:https://www.cnblogs.com/li666/p/11131277.html