同步代码块synchronized 的使用

实现Runnable接口
如何获取线程名称
如何给线程设置名称
实现接口方式的好处
可以避免由于Java单继承带来的局限性。
适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想。
package cn.itcast_05;

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			// 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
			System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}

}
package cn.itcast_05;

/*
 * 方式2:实现Runnable接口
 * 步骤:
 * 		A:自定义类MyRunnable实现Runnable接口
 * 		B:重写run()方法
 * 		C:创建MyRunnable类的对象
 * 		D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
 */
public class MyRunnableDemo {
	public static void main(String[] args) {
		// 创建MyRunnable类的对象
		MyRunnable my = new MyRunnable();

		// 创建Thread类的对象,并把C步骤的对象作为构造参数传递
		// Thread(Runnable target)
		// Thread t1 = new Thread(my);
		// Thread t2 = new Thread(my);
		// t1.setName("林青霞");
		// t2.setName("刘意");

		// Thread(Runnable target, String name)
		Thread t1 = new Thread(my, "林青霞");
		Thread t2 = new Thread(my, "刘意");

		t1.start();
		t2.start();
	}
}

问题描述(使用窗口售票的问题引入多线程的问题):

package cn.itcast_06;

public class SellTicket extends Thread {

	// 定义100张票
	// private int tickets = 100;
	// 为了让多个线程对象共享这100张票,我们其实应该用静态修饰
	private static int tickets = 100;

	@Override
	public void run() {
		// 定义100张票
		// 每个线程进来都会走这里,这样的话,每个线程对象相当于买的是自己的那100张票,这不合理,所以应该定义到外面
		// int tickets = 100;

		// 是为了模拟一直有票
		while (true) {
			if (tickets > 0) {
				System.out.println(getName() + "正在出售第" + (tickets--) + "张票");
			}
		}
	}
}
package cn.itcast_06;

/*
 * 某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
 * 继承Thread类来实现。
 */
public class SellTicketDemo {
	public static void main(String[] args) {
		// 创建三个线程对象
		SellTicket st1 = new SellTicket();
		SellTicket st2 = new SellTicket();
		SellTicket st3 = new SellTicket();

		// 给线程对象起名字
		st1.setName("窗口1");
		st2.setName("窗口2");
		st3.setName("窗口3");

		// 启动线程
		st1.start();
		st2.start();
		st3.start();
	}
}
窗口1正在出售第100张票
窗口3正在出售第99张票
窗口1正在出售第98张票
窗口3正在出售第97张票
窗口1正在出售第96张票
窗口3正在出售第95张票
#error1 问题1:窗口3应该出售 第94张票的
窗口3正在出售第93张票
窗口3正在出售第92张票
窗口3正在出售第91张票
窗口3正在出售第90张票
窗口3正在出售第89张票
窗口3正在出售第88张票
窗口3正在出售第87张票
窗口3正在出售第86张票
窗口3正在出售第85张票
窗口3正在出售第84张票
#error2: 窗口1应该出售第83张票的
窗口1正在出售第94张票
窗口1正在出售第82张票
窗口1正在出售第81张票
窗口1正在出售第80张票
窗口3正在出售第83张票
窗口1正在出售第78张票
窗口1正在出售第76张票
窗口1正在出售第75张票
窗口1正在出售第74张票
窗口1正在出售第73张票
窗口1正在出售第72张票
窗口1正在出售第71张票
窗口1正在出售第70张票
窗口1正在出售第69张票
窗口1正在出售第68张票
窗口1正在出售第67张票
窗口1正在出售第66张票
窗口1正在出售第65张票
窗口1正在出售第64张票
窗口1正在出售第63张票
窗口1正在出售第62张票
窗口1正在出售第61张票
窗口2正在出售第79张票
窗口3正在出售第77张票
窗口1正在出售第59张票
窗口3正在出售第58张票
窗口3正在出售第56张票
窗口3正在出售第55张票
窗口3正在出售第54张票
窗口3正在出售第53张票
窗口3正在出售第52张票
窗口3正在出售第51张票
窗口3正在出售第50张票
窗口3正在出售第49张票
窗口3正在出售第48张票
窗口3正在出售第47张票
窗口3正在出售第46张票
窗口3正在出售第45张票
窗口3正在出售第44张票
窗口3正在出售第43张票
窗口3正在出售第42张票
窗口3正在出售第41张票
窗口3正在出售第40张票
窗口3正在出售第39张票
窗口3正在出售第38张票
窗口3正在出售第37张票
窗口3正在出售第36张票
窗口3正在出售第35张票
窗口3正在出售第34张票
窗口3正在出售第33张票
窗口3正在出售第32张票
窗口3正在出售第31张票
窗口3正在出售第30张票
窗口3正在出售第29张票
窗口3正在出售第28张票
窗口3正在出售第27张票
窗口3正在出售第26张票
窗口3正在出售第25张票
窗口3正在出售第24张票
窗口3正在出售第23张票
窗口3正在出售第22张票
窗口3正在出售第21张票
窗口3正在出售第20张票
窗口3正在出售第19张票
窗口3正在出售第18张票
窗口3正在出售第17张票
窗口3正在出售第16张票
窗口3正在出售第15张票
窗口3正在出售第14张票
窗口3正在出售第13张票
窗口3正在出售第12张票
窗口3正在出售第11张票
窗口3正在出售第10张票
窗口3正在出售第9张票
窗口3正在出售第8张票
窗口3正在出售第7张票
窗口3正在出售第6张票
窗口3正在出售第5张票
窗口3正在出售第4张票
窗口3正在出售第3张票
窗口3正在出售第2张票
窗口3正在出售第1张票
窗口2正在出售第60张票
窗口1正在出售第57张票

问题的根因是:多个线程同时操作一个资源,导致数据产生混乱,解决方案是 将操作统一个资源的位置将数据锁起来

问题解决:

package cn.itcast_09;

public class SellTicket implements Runnable {
	// 定义100张票
	private int tickets = 100;
	//创建锁对象
	private Object obj = new Object();

	@Override
	public void run() {
		while (true) {
			synchronized (obj) {
				if (tickets > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()
							+ "正在出售第" + (tickets--) + "张票");
				}
			}
		}
	}
}
package cn.itcast_09;

/*
 * 如何解决线程安全问题呢?
 * 
 * 要想解决问题,就要知道哪些原因会导致出问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)
 * A:是否是多线程环境
 * B:是否有共享数据
 * C:是否有多条语句操作共享数据
 * 
 * 我们来回想一下我们的程序有没有上面的问题呢?
 * A:是否是多线程环境	是
 * B:是否有共享数据	是
 * C:是否有多条语句操作共享数据	是
 * 
 * 由此可见我们的程序出现问题是正常的,因为它满足出问题的条件。
 * 接下来才是我们要想想如何解决问题呢?
 * A和B的问题我们改变不了,我们只能想办法去把C改变一下。
 * 思想:
 * 		把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
 * 问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。
 * 
 * 同步代码块:
 * 		synchronized(对象){
 * 			需要同步的代码;
 * 		}
 * 
 * 		A:对象是什么呢?
 * 			我们可以随便创建一个对象试试。
 * 		B:需要同步的代码是哪些呢?
 * 			把多条语句操作共享数据的代码的部分给包起来
 * 
 * 		注意:
 * 			同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
 * 			多个线程必须是同一把锁。
 */
public class SellTicketDemo {
	public static void main(String[] args) {
		// 创建资源对象
		SellTicket st = new SellTicket();

		// 创建三个线程对象
		Thread t1 = new Thread(st, "窗口1");
		Thread t2 = new Thread(st, "窗口2");
		Thread t3 = new Thread(st, "窗口3");

		// 启动线程
		t1.start();
		t2.start();
		t3.start();
	}
}
窗口1正在出售第100张票
窗口1正在出售第99张票
窗口1正在出售第98张票
窗口1正在出售第97张票
窗口1正在出售第96张票
窗口1正在出售第95张票
窗口1正在出售第94张票
窗口1正在出售第93张票
窗口1正在出售第92张票
窗口1正在出售第91张票
窗口1正在出售第90张票
窗口1正在出售第89张票
窗口1正在出售第88张票
窗口1正在出售第87张票
窗口1正在出售第86张票
窗口1正在出售第85张票
窗口1正在出售第84张票
窗口1正在出售第83张票
窗口1正在出售第82张票
窗口2正在出售第81张票
窗口2正在出售第80张票
窗口3正在出售第79张票
窗口3正在出售第78张票
窗口3正在出售第77张票
窗口3正在出售第76张票
窗口3正在出售第75张票
窗口3正在出售第74张票
窗口3正在出售第73张票
窗口3正在出售第72张票
窗口3正在出售第71张票
窗口3正在出售第70张票
窗口3正在出售第69张票
窗口3正在出售第68张票
窗口3正在出售第67张票
窗口3正在出售第66张票
窗口3正在出售第65张票
窗口3正在出售第64张票
窗口3正在出售第63张票
窗口3正在出售第62张票
窗口3正在出售第61张票
窗口3正在出售第60张票
窗口3正在出售第59张票
窗口3正在出售第58张票
窗口3正在出售第57张票
窗口3正在出售第56张票
窗口3正在出售第55张票
窗口3正在出售第54张票
窗口3正在出售第53张票
窗口2正在出售第52张票
窗口2正在出售第51张票
窗口2正在出售第50张票
窗口1正在出售第49张票
窗口1正在出售第48张票
窗口1正在出售第47张票
窗口1正在出售第46张票
窗口1正在出售第45张票
窗口2正在出售第44张票
窗口2正在出售第43张票
窗口2正在出售第42张票
窗口2正在出售第41张票
窗口2正在出售第40张票
窗口2正在出售第39张票
窗口3正在出售第38张票
窗口3正在出售第37张票
窗口3正在出售第36张票
窗口3正在出售第35张票
窗口3正在出售第34张票
窗口2正在出售第33张票
窗口2正在出售第32张票
窗口2正在出售第31张票
窗口2正在出售第30张票
窗口2正在出售第29张票
窗口2正在出售第28张票
窗口2正在出售第27张票
窗口2正在出售第26张票
窗口2正在出售第25张票
窗口2正在出售第24张票
窗口2正在出售第23张票
窗口2正在出售第22张票
窗口1正在出售第21张票
窗口1正在出售第20张票
窗口1正在出售第19张票
窗口1正在出售第18张票
窗口2正在出售第17张票
窗口2正在出售第16张票
窗口2正在出售第15张票
窗口2正在出售第14张票
窗口3正在出售第13张票
窗口3正在出售第12张票
窗口3正在出售第11张票
窗口3正在出售第10张票
窗口3正在出售第9张票
窗口3正在出售第8张票
窗口3正在出售第7张票
窗口3正在出售第6张票
窗口3正在出售第5张票
窗口3正在出售第4张票
窗口3正在出售第3张票
窗口3正在出售第2张票
窗口3正在出售第1张票

解决了

猜你喜欢

转载自blog.csdn.net/nmjhehe/article/details/88385889