线程4

线程的同步
使用多线程模拟火车站售票程序,开启三个窗口售票。

public class Tick implements Runnable{
	private  static int  num = 100;
	@Override
	public void run() {
		 while(true) {
			 if(num > 0) {
				 try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				 System.out.println(Thread.currentThread().getName()+"销售车票座位号为:" + num--); 
			 }else {
				 break;
			 }
			
		 }
	}

}
//此时创建三个线程 表示三个售票窗口
public class SaleTicket {
	public static void main(String[] args) {
		Thread t1 = new Thread(new Tick(),"1号窗口");
		Thread t2 = new Thread(new Tick(),"2号窗口");
		Thread t3 = new Thread(new Tick(),"3号窗口");
		Thread t4 = new Thread(new Tick(),"4号窗口");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。
解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
如何实现线程同步:
1 同步方法
2 同步代码块
Synchronized java对于多线程的安全问题提供了专业的解决方式:同步机制

使用同步代码块来实现线程同步

public static void main(String[] args) {
		Object obj = new Object();
		Thread t1 = new Thread() {
			public void run() {
				while(true) {
				synchronized(obj){
						System.out.print("中");
						System.out.print("北");
						System.out.print("大");
						System.out.print("学");
						System.out.println();
					}
				}	
			};
		};
		Thread  t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
				synchronized (obj) {//synchronized (同步锁)
				
						System.out.print("蓝");
						System.out.print("桥");
						System.out.print("软");
						System.out.print("件");
						System.out.print("学");
						System.out.print("院");
						System.out.println();
					}
				}
			}
		});
		t1.start();
		t2.start();
	}
}

在同步代码块中 同步锁/线程锁由谁来担当?
在同步代码块中 锁是一个对象 而且可以是任意对象
在同步代码块中 锁对象必须是同一个对象
也可以使用本类的字节码文件对象
静态方法的同步代码块 的锁对象:
可以是任意的静态对象都可以 必须是同一个对象
可以使用本类的字节码文件对象

什么时候可以使用this来作为同步锁:

public class SynchronizedTest {
	//static String s = "aa";
	
	public static void main(String[] args) {
		SynchronizedTest st = new SynchronizedTest();
		st.show1();
		st.show2();
	}
	
	public  void show1() {//同步方法
		 new Thread() {
			public void run() {
				while(true) {
						print1();
					}
			
			};
		}.start();
	}
	public void show2() {
	  new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true) {
						print2();
				}
			}
		}).start();
	}
	
	public  void print1() {
		synchronized (this) {
			System.out.print("中");
			System.out.print("北");
			System.out.print("大");
			System.out.print("学");
			System.out.println();
		}
		
	}
	public   void print2() {
		synchronized (this) {
			System.out.print("蓝");
			System.out.print("桥");
			System.out.print("软");
			System.out.print("件");
			System.out.print("学");
			System.out.print("院");
			System.out.println();
		}
		
	}
}

同步方法
同步方法中的锁对象是谁?

public synchronized void print1() {

			System.out.print("中");
			System.out.print("北");
			System.out.print("大");
			System.out.print("学");
			System.out.println();
		
		
	}
	public  void print2() {
			synchronized (this) {
				System.out.print("蓝");
				System.out.print("桥");
				System.out.print("软");
				System.out.print("件");
				System.out.print("学");
				System.out.print("院");
				System.out.println();
			}
			
		
		
	}

通过上述代码 证明同步方法中的锁对象是this
静态同步方法的锁对象是谁?

public static  synchronized void print1() {

			System.out.print("中");
			System.out.print("北");
			System.out.print("大");
			System.out.print("学");
			System.out.println();
		
		
	}
	public static   void print2() {
			synchronized (SynchronizedTest.class) {
				System.out.print("蓝");
				System.out.print("桥");
				System.out.print("软");
				System.out.print("件");
				System.out.print("学");
				System.out.print("院");
				System.out.println();
			}
			
		
		
	}

通过上述代码 证明静态同步方法中的锁对象是本类的字节码对象

总结: 
1 什么时候使用同步?
当多个线程操作共享数据时  就需要线程同步。
2 线程同步的方式:同步代码块  同步方法 可以时静态也可以时非静态
3 同步代码块的锁对象?
     当在非静态方法中 对存在线程安全问题的代码实行同步策略 此时的锁对象可以是任意对象 只需要保证所有的线程使用的是同一个锁对象  this也可以充当锁对象
    在静态代码块中  可以使用静态对象来作为锁对象  保证所有的线程使用的是同一个锁对象 
    
4 同步方法的锁对象?
  对于非静态方法  锁对象为this
 对于静态方法  字节码对象  本类的class对象

线程中需要避免的问题:死锁

public static void main(String[] args) {
		String lock1 = "aaa";
		String lock2 = "bbb";
	 new Thread() {
			@Override
			public void run() {
				while(true) {
					synchronized (lock1) {
						System.out.println("AAAA");
						synchronized (lock2) {
							System.out.println("BBBB");
						}
					}
				}
			}
		}.start();
		
		new Thread() {
			@Override
			public void run() {
				while(true) {
					synchronized (lock2) {
						System.out.println("CCCCCCCCCCCCCCCCCCCCC");
						synchronized (lock1) {
							System.out.println("DDDDDDDDDDDDDDDDDDDD");
						}
					}
				}
			}
		}.start();
	}

死锁是如何出现的:死锁的出现是因为锁的嵌套

在开发中 应尽量避免死锁的出现 应尽量不要使用锁的嵌套

锁在什么时候会被释放?
1 同步的代码执行结束
2 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、 该方法的继续执行。
3当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导 致异常结束。
4当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线 程暂停,并释放锁。
不会释放锁的操作
线程执行同步代码块或同步方法时,程序调用Thread.sleep()、 Thread.yield()方法暂停当前线程的执行
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程 挂起,该线程不会释放锁(同步监视器)。
应尽量避免使用suspend()和resume()来控制线程
单例设计模式:
1 将构造器私有化
2 提供一个该类的静态变量(类型为当前类)
3 提供对外获取该类实例对象的方法
饿汉:

// 饿汉式 是否存在线程安全问题  不存在
public class Singleton1 {
	private static Singleton1 instance = new Singleton1();
	
	private Singleton1() {	
	}
	public static Singleton1 getInstance() {
		return instance;
	}
}

懒汉:

//懒汉式  是否存在线程问题  存在
//如何解决  使用线程同步
public class Singleton2 {
private static Singleton2 instance = null;
	
	private Singleton2() {	
	}
	public static Singleton2 getInstance() {
		synchronized (Singleton2.class) {
				if(instance == null) {
				instance = new Singleton2();
		}
			
	 }
		return instance;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值