线程安全

来源:互联网 发布:ultraiso软件有多大 编辑:程序博客网 时间:2024/05/16 06:02

【代码仅仅供本人学习】

第一:

/* * 某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有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();}}public class SellTicket extends Thread {// 定义100张票// private int tickets = 100;// 为了让多个线程对象共享这100张票,我们其实应该用静态修饰private static int tickets = 100;@Overridepublic void run() {// 定义100张票// 每个线程进来都会走这里,这样的话,每个线程对象相当于买的是自己的那100张票,这不合理,所以应该定义到外面// int tickets = 100;// 是为了模拟一直有票while (true) {if (tickets > 0) {System.out.println(getName() + "正在出售第" + (tickets--) + "张票");}}}}


第二:


/* * 实现Runnable接口的方式实现 */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();}}public class SellTicket implements Runnable {// 定义100张票private int tickets = 100;@Overridepublic void run() {while (true) {if (tickets > 0) {System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票");}}}}

第三:


/* * 实现Runnable接口的方式实现 *  * 通过加入延迟后,就产生了连个问题: * A:相同的票卖了多次 * CPU的一次操作必须是原子性的 * 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();}}public class SellTicket implements Runnable {// 定义100张票private int tickets = 100;/*@Overridepublic void run() {while (true) {// t1,t2,t3三个线程// 这一次的tickets = 100;if (tickets > 0) {// 为了模拟更真实的场景,我们稍作休息try {Thread.sleep(100); // t1就稍作休息,t2就稍作休息} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票"); 理想状态: 窗口1正在出售第100张票 窗口2正在出售第99张票 但是呢? CPU的每一次执行必须是一个原子性(最简单基本的)的操作。 先记录以前的值 接着把ticket-- 然后输出以前的值(t2来了) ticket的值就变成了99 窗口1正在出售第100张票 窗口2正在出售第100张票}}}*/@Overridepublic void run() {while (true) {// t1,t2,t3三个线程// 这一次的tickets = 1;if (tickets > 0) {// 为了模拟更真实的场景,我们稍作休息try {Thread.sleep(100); //t1进来了并休息,t2进来了并休息,t3进来了并休息,} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票");//窗口1正在出售第1张票,tickets=0//窗口2正在出售第0张票,tickets=-1//窗口3正在出售第-1张票,tickets=-2}}}}

第四:


public class SellTicket implements Runnable {// 定义100张票private int tickets = 100;//创建锁对象private Object obj = new Object();/*@Overridepublic void run() {while (true) {synchronized(new Object()){if (tickets > 0) {try {Thread.sleep(100); } catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ (tickets--) + "张票");}}}}*/@Overridepublic 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--) + "张票");}}}}}/* * 如何解决线程安全问题呢? *  * 要想解决问题,就要知道哪些原因会导致出问题:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准) * 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();}}

第五:


/* * 举例: * 火车上厕所。 *  * 同步的特点: * 前提: * 多个线程 *解决问题的时候要注意: *多个线程使用的是同一个锁对象 * 同步的好处  *同步的出现解决了多线程的安全问题。 * 同步的弊端 *当线程相当多时,因为每个线程都会去判断同步上的锁, *       这是很耗费资源的,无形中会降低程序的运行效率。 */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();}}public class SellTicket implements Runnable {// 定义100张票private int tickets = 100;// 定义同一把锁private Object obj = new Object();@Overridepublic void run() {while (true) {// t1,t2,t3都能走到这里// 假设t1抢到CPU的执行权,t1就要进来// 假设t2抢到CPU的执行权,t2就要进来,发现门是关着的,进不去。所以就等着。// 门(开,关)synchronized (obj) { // 发现这里的代码将来是会被锁上的,所以t1进来后,就锁了。(关)if (tickets > 0) {try {Thread.sleep(100); // t1就睡眠了} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");//窗口1正在出售第100张票}} //t1就出来可,然后就开门。(开)}}}

第六:


/* * A:同步代码块的锁对象是谁呢? * 任意对象。 *  * B:同步方法的格式及锁对象问题? * 把同步关键字加在方法上。 *  * 同步方法是谁呢? * this *  * C:静态方法及锁对象问题? * 静态方法的锁对象是谁呢? * 类的字节码文件对象。(反射会讲) */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();}}public class SellTicket implements Runnable {// 定义100张票private static int tickets = 100;// 定义同一把锁private Object obj = new Object();private Demo d = new Demo();private int x = 0;/*//同步代码块用obj做锁@Overridepublic 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--) + "张票 ");}}}}*///同步代码块用任意对象做锁/*@Overridepublic void run() {while (true) {synchronized (d) {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");}}}}*/@Overridepublic void run() {while (true) {if(x%2==0){synchronized (SellTicket.class) {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");}}}else {/*synchronized (d) {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");}}*/sellTicket();}x++;}}/*private void sellTicket() {synchronized (d) {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");}}}*///如果一个方法一进去就看到了代码被同步了,那么我就再想能不能把这个同步加在方法上呢?/* private synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");}}*/private static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");}}}class Demo {}


第八:线程安全的判断


import java.util.ArrayList;import java.util.Collections;import java.util.Hashtable;import java.util.List;import java.util.Vector;public class ThreadDemo {public static void main(String[] args) {// 线程安全的类StringBuffer sb = new StringBuffer();Vector<String> v = new Vector<String>();Hashtable<String, String> h = new Hashtable<String, String>();// Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你// 那么到底用谁呢?// public static <T> List<T> synchronizedList(List<T> list)List<String> list1 = new ArrayList<String>();// 线程不安全List<String> list2 = Collections.synchronizedList(new ArrayList<String>()); // 线程安全}}






















0 0
原创粉丝点击