synchronized同步锁的三种方式

不多说,直接上代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *  铁道部发布了一个售票任务,要求销售1000张票,要求有5个窗口来进行销售,请编写多线程程序来模拟这个效果
 *
 *问题1:出现部分重票
 *原因:语句未加锁,整体未执行完,被下个线程访问
 *
 *解决:加锁---锁的范围:锁打印和++
 *	      ---锁的对象:同一个对象
 *锁的分类:
 *1.同步代码块2.同步方法3.对象互斥锁
 *
 *问题二:票数超出范围
 *解决:在锁内加判断
 *
 *问题三:每个线程应该都有同一个出口
 *解决:使用while(true)循环
 */
class Task1 implements Runnable{
	private int ticket = 0 ;

	private Lock lock = new ReentrantLock();
	
	public void run() {
		
		//1.同步代码块
		//save1();
		
/*		//2.同步方法
		while(true){
			if(save2())
				break;
		}*/
		
		//方法3:互斥对象锁---容易死锁  alt+shift+m 封装方法快捷键
		//1.同一把锁  2.锁的范围
		while(true){
			try{
				lock.lock();//加锁
				if(ticket<10){
					ticket++;
					System.out.println("窗口"+Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
				}else {
					System.out.println(Thread.currentThread().getName()+"已售完。。");
					break;
				}
			}finally {
				lock.unlock();
			}
		}
}

	//1.同步代码块	---1.锁的对象2.锁的范围
	private void save1() {
		while(true){
			synchronized (this) {//"lock"  obj---同一个对象
				if(ticket<10){
					ticket++;
					System.out.println("窗口"+Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
				}else {
					System.out.println(Thread.currentThread().getName()+"已售完。。");
					break;
				}
			}
		}
	}
	
	//2.同步方法         
	//1,锁的对象2.锁的范围
	private synchronized boolean save2() {
		if(ticket<10){
			ticket++;
			System.out.println("窗口"+Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
			return false;
		}else {
			System.out.println(Thread.currentThread().getName()+"已售完。。");
			return true;
		}
	}
}

public class Test1 {
	public static void main(String[] args) {
		Task1 task1 = new Task1();
		for(int i=1;i<=5;i++){
			new Thread(task1,(Integer.toString(i))).start();
		}
		
		
		//----------回顾线程安全-----------
		//StringBuffer--用在多线程
		StringBuffer sb = new StringBuffer();
		sb.append("hello");
		
		//StringBuilder--用在单线程
		StringBuilder sb2 = new StringBuilder();
		sb2.append("hello");
		
		//我们所学的集合是线程安全的吗?  ArrayList---不安全
		List list = new ArrayList<>();
		list.add("hello");
		
		//---集合的线程安全:---------
		list = Collections.synchronizedList(new ArrayList<>());
		list.add("hello");
	}
}

下面是继承Thread实现

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 问题1:会重复卖5000张票
 * 原因:有5个成员属性ticket---每个对象都有一份独立的成员属性
 * 解决:加static
 *
 *问题2:有部分重票
 *原因:锁的不是同一个对象
 *解决:锁字符串或静态对象
 *
 */
class MyThread extends Thread{
	private static int ticket = 1;
	private static Object obj = new Object();
	private static Lock lock = new ReentrantLock();
	
	public MyThread(String name) {
		super(name);
	}
	@Override
	public void run() {
		//1.同步代码块
		//save1();
		
		//2.同步方法
		while(true){
			if(save2())
				break;
		}
		
		//3.对象互斥锁
		//save3();
	}
	
	//1.同步代码块
	private void save1() {
		while(true){
			synchronized (obj) {//"lock"  静态对象obj
				if(ticket<=1000){
					System.out.println("窗口"+getName()+"正在销售第"+ticket+"张票");
					ticket++;
				}else {
					System.out.println("窗口"+getName()+"已售完。。");
					break;
				}
			}
		}
	}
	
	//2.同步方法
	private static synchronized boolean save2(){
		if(ticket<=10){
			System.out.println("窗口"+Thread.currentThread().getName()+"正在销售第"+ticket+"张票");
			ticket++;
			return false;
		}else {
			System.out.println("窗口"+Thread.currentThread().getName()+"已售完。。");
			return true;
		}
	}
	
	//3.对象互斥锁
	private void save3() {
		while(true){
			try {
				lock.lock();
				if(ticket<=1000){
					System.out.println("窗口"+getName()+"正在销售第"+ticket+"张票");
					ticket++;
				}else {
					System.out.println("窗口"+getName()+"已售完。。");
					break;
				}
			} finally {
				lock.unlock();
			}
		}
	}
}

public class TicketTest2 {
	public static void main(String[] args) throws InterruptedException {
		for(int i=1;i<=5;i++){
			new MyThread(Integer.toString(i)).start();
		}
	}
}

总结:
加锁牢记两点:1.锁的对象2.锁的范围

实现runnable接口 VS 继承Thread类
runnable接口: 不用锁静态对象,同一个任务 能确定是同一个对象
继承Thread类:需要锁静态对象,才能确保是同一个对象

你可能感兴趣的:(synchronized同步锁的三种方式)