Java-如何解决多线程当中共享资源的冲突问题

解决多线程当中共享资源冲突的问题

1. 冲突问题展示:

/*
 * 共享资源冲突的问题
 */
class SingleThread implements Runnable {

	// 共享资源,100张票
	private static int ticket = 100;

	@Override
	public void run() {
		while (true) {
			if (ticket > 0) {
				System.out.println(Thread.currentThread().getName() +
				 "售出了第" + ticket + "张票");
				ticket -= 1;
				
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				System.out.println(Thread.currentThread().getName() +
				 "售罄!!!");
				break;
			}
		}
	}
}

public class Demo1 {
	public static void main(String[] args) {
		Thread thread = new Thread(new SingleThread(),"淘票票");
		Thread thread2 = new Thread(new SingleThread(),"猫眼");
		Thread thread3 = new Thread(new SingleThread(),"美团");
		
		thread.start();
		thread2.start();
		thread3.start();
	}
}

Java-如何解决多线程当中共享资源的冲突问题_第1张图片
Java-如何解决多线程当中共享资源的冲突问题_第2张图片
从上面的例子上可以看到,最后一张票被每一个平台都卖了一次,这样子肯定是不符合实际情况的,这就是本次我们需要解决的问题。

2. 解决方法:

2.1 同步代码块
  1. 格式:
synchronized ("锁") {
	//需要同步的代码
}
  1. 特征:
    a: synchronized关键字后面的小括号里面的对象是锁对象,并且要求如果是多线程的情况下,锁对象必须是唯一的
    b: synchronized后大括号中的代码就是需要同步的代码,或者说加锁的代码,大括号里面的内容一次有且只允许一个线程类对象进入执行的操作,其余的线程类对象需要等待该线程类对象开锁才能进入。
    c: 同步代码块中的代码越短越好,在保证足够安全的情况下,提高性能。
// 1. 使用同步代码块解决多线程中共享资源冲突的问题
 
/**
 * 自定义售票线程类
 * 
 * @author 
 *
 */
//同步代码块
class SingleThread1 implements Runnable {

	// 共享资源,100张票
	private static int ticket = 100;

	@Override
	public void run() {
		while (true) {
			synchronized ("锁") {

				if (ticket > 0) {
					System.out.println(Thread.currentThread().getName() +
					 "售出了第" + ticket + "张票");
					ticket -= 1;

					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					System.out.println(Thread.currentThread().getName() +
					 "售罄!!!");
					break;
				}
			}
		}
	}
}

public class Demo2 {
	public static void main(String[] args) {
		Thread thread = new Thread(new SingleThread1(), "淘票票");
		Thread thread2 = new Thread(new SingleThread1(), "猫眼");
		Thread thread3 = new Thread(new SingleThread1(), "美团");

		thread.start();
		thread2.start();
		thread3.start();
	}
}
2.2 同步方法
  • 什么是同步方法:使用synchronized关键字修饰的方法就是同步方法,同步方法一次有且只允许一个线程类对象进入执行操作。
2.2.1 静态同步方法
  • 静态方法使用synchronized关键字修饰就是静态同步方法,静态同步方法的锁对象是当前类对应的字节码文件,是唯一的。
  • 如果是选择静态同步方法的话,因为锁对象是.class字节码文件,具有唯一性,多个线程使用的锁是同一个。
// 2.1 使用静态成员方法解决多线程中共享资源冲突的问题
/**
 * 自定义售票线程类
 * 
 * @author 
 *
 */
//同步方法
class SingleThread3 implements Runnable {

	// 共享资源,100张票
	private static int ticket = 100;

	@Override
	public void run() {
		while (true) {
			sellTicket();
			if(ticket <= 0) {
				break;
			}
		}
	}

	// 静态同步方法
	public static synchronized void sellTicket() {
		if (ticket > 0) {
			System.out.println(Thread.currentThread().getName() +
			 "售出了第" + ticket + "张票");
			ticket -= 1;

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			System.out.println(Thread.currentThread().getName() + "售罄!!!");
		}
	}
}

public class Demo3 {
	public static void main(String[] args) {
	//使用静态同步方法
		Thread thread1 = new Thread(new SingleThread3(), "淘票票");
		Thread thread2 = new Thread(new SingleThread3(), "猫眼");
		Thread thread3 = new Thread(new SingleThread3(), "美团");

		thread1.start();
		thread2.start();
		thread3.start();
	}
}
2.2.2 非静态同步方法
  • 非静态方法使用synchronized关键字修饰的就是非静态同步方法,非静态同步方法的锁对象是当前类对象 - this
  • 如果是非静态同步方法的话,需要保证执行的线程类对象目标代码只有一个,因为锁对象为当前类对象。
// 2.2 使用静态成员方法解决多线程中共享资源冲突的问题
/**
 * 自定义售票线程类
 * 
 * @author 
 *
 */
//同步方法
class SingleThread3 implements Runnable {

	// 共享资源,100张票
	private static int ticket = 100;

	@Override
	public void run() {
		while (true) {
			sellTicket();
			if(ticket <= 0) {
				break;
			}
		}
	}
	
	//非静态同步方法
	public synchronized void sellTicket() {
		if (ticket > 0) {
			System.out.println(Thread.currentThread().getName() +
			 "售出了第" + ticket + "张票");
			ticket -= 1;

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			System.out.println(Thread.currentThread().getName() +
			 "售罄!!!");
		}
	}

}

public class Demo3 {
	public static void main(String[] args) {
		//使用非静态同步方法
		//使用同一个目标代码对象
		SingleThread3 singleThread3 = new SingleThread3();
		Thread thread1 = new Thread(singleThread3,"淘票票");
		Thread thread2 = new Thread(singleThread3,"猫眼");
		Thread thread3 = new Thread(singleThread3,"美团");
	}
}
2.3 Lock锁
  1. 对象化操作:Lock lock = new ReentramtLock( );
  2. 加锁:lock.lock( );
  3. 开锁:lock.unlock( );
// 使用静态Lock锁解决共享资源冲突的问题
/**
 * 自定义售票线程类
 * 
 * @author 
 *
 */
//lock加锁操作
class SingleThread4 implements Runnable {

	// 共享资源,100张票
	private static int ticket = 100;
	
	//创建锁对象,这里使用的是静态的方式,锁对象是唯一的
	static Lock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {
				
			//加锁
			lock.lock();
				if (ticket > 0) {
					System.out.println(Thread.currentThread().getName() +
					 "售出了第" + ticket + "张票");
					ticket -= 1;

					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					System.out.println(Thread.currentThread().getName() +
					 "售罄!!!");
					break;
				}
			lock.unlock();
		}
	}
}

public class Demo4 {
	public static void main(String[] args) {
		Thread thread = new Thread(new SingleThread4(), "淘票票");
		Thread thread2 = new Thread(new SingleThread4(), "猫眼");
		Thread thread3 = new Thread(new SingleThread4(), "美团");

		thread.start();
		thread2.start();
		thread3.start();
	}
}

你可能感兴趣的:(Java-如何解决多线程当中共享资源的冲突问题)