JAVA线程总结( 二)

继续上篇的总结,这次我们讲线程同步机制

线程同步是为了确保线程安全,所谓线程安全指的是多个线程对同一资源进行访问时,有可能产生数据不一致问题,导致线程访问的资源并不是安全的。如果多线程程序运行结果和单线程运行的结果是一样的,且相关变量的值与预期值一样,则是线程安全的。

举个简单的例子,后边会写到这个例子,铁路售票,分四个窗口卖,一共一百张,需要同步。

线程同步机制包括同步代码块和同步方法两种。

1.同步代码块

package com.tao.syn;

public class Demo1_Synchronized {
	public static void main(String[] args) {
		final Printer p=new Printer();
		new Thread(){
			public void run(){
				for(int i=1;i<100;i++){
					p.print1();
				}
			}
		}.start();
		
		new Thread(){
			public void run(){
				for(int i=1;i<100;i++){
					p.print2();
				}
			}
		}.start();
	}

}
class Demo{
	
}
class Printer {
	Demo d=new Demo();
	public void print1(){
		synchronized (d) {             //同步代码块,锁机制,锁对象可以是任意的
			System.out.print("清");
		System.out.print("华");
		System.out.print("大");
		System.out.print("学");
		System.out.println();
		}	
	}
	public void print2(){
		synchronized (d) {        //	synchronized (new Demo())不可行,因为不是同一对象了      
			System.out.print("我");
		System.out.print("爱");
		System.out.print("你");
		System.out.println();
		}
		
	}
}

2.同步方法

package com.tao.syn;

public class Demo2_Synchronized {
	/*
	        非静态的同步方法的锁对象是神马?
		答:非静态的同步方法的锁对象是this 
		静态的同步方法的锁对象是什么?
		是该类的字节码对象
	 */
	public static void main(String[] args) {
		final Printer p=new Printer();
		new Thread(){
			public void run(){
				for(int i=1;i<1000;i++){
					p.print1();
				}
			}
		}.start();
		
		new Thread(){
			public void run(){
				for(int i=1;i<1000;i++){
					p.print2();
				}
			}
		}.start();
	}

}
class Demo2{
	
}
class Printer2 {
	Demo d=new Demo();
	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 (Printer2.class) {        //	synchronized (new Demo())不可行,因为不是同一对象了      
			System.out.print("我");
		System.out.print("爱");
		System.out.print("你");
		System.out.println();
		}
		
	}
}
铁路卖票的例子
package com.tao.syn;
/**
 * 
 * @author 天外飞星
 * 铁路卖票,四个窗口,一共100张
 *
 */
public class Demo3_Ticket {
	public static void main(String[] args) {
		new Ticket().start();    //开启四条线程,即四个窗口
		new Ticket().start();
		new Ticket().start();
		new Ticket().start();
	}
}	
class Ticket extends Thread{
	private static int ticket=100;    //必须设置为static的,四个线程共享ticket
	public void run(){
		while(true){
			synchronized (Ticket.class) {    //只能class,因为使用对象的话,每个Ticket都会创建一个
				if(ticket==0){
				try {
					Thread.sleep(10); 
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;
			}
			}		
			System.out.println("卖第"+ticket--+"张票");
		}
	}
}

单例设计模式

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

具体实现

需要:

(1)将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

(2)在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。

(3)定义一个静态方法返回这个唯一对象。

实现一:立即加载 / “饿汉模式”
package com.tao.thread;

public class Demo2_Singleton1 {
	public static void main(String[] args) {
		Singleton1 s2 = Singleton1.getInstance();
		// Singleton.s1=null;
		Singleton1 s3 = Singleton1.getInstance();
		System.out.println(s2 == s3);
	}
}

class Singleton1 {
	// 1.私有构造方法,其他类不能访问该类构造方法
	private Singleton1() {
	};

	/*
	 * 一、饿汉式(常用)
	 */
	// 2.创建本类对象
	private static Singleton1 s1 = new Singleton1();

	// 3.对外提供公共的访问方法
	public static Singleton1 getInstance() { // 获取实例
		return s1;
	}
}
实现二:延迟加载 / “懒汉模式”
package com.tao.thread;

public class Demo3_Singleton2 {
	public static void main(String[] args) {
		Singleton2 s2 = Singleton2.getInstance();
		// Singleton.s1=null;
		Singleton2 s3 = Singleton2.getInstance();
		System.out.println(s2 == s3);
	}
}

class Singleton2 {
	// 1.私有构造方法,其他类不能访问该类构造方法
	private Singleton2() {
	};

	/*
	 * 二、懒汉式
	 */
	// 2.创建本类对象
	private static Singleton2 s1;
	public static Singleton2 getInstance(){		
		if(s1==null){ 
			//线程1等待,线程2等待可能会导致创建两个对象 ,平时不用,面试用
			s1=new Singleton2();
		}
		return s1;
	}
}

实现三、final修饰方法

package com.tao.thread;
/**
 *  三、final修饰方法
 * @author 天外飞星

 *
 */
public class Demo4_Singleton3 {
	public static void main(String[] args) {
		Singleton4 s2=Singleton4.s1;     //	 成员变量被私有,不能通过类名.调用
	//	Singleton4 s1=null;																	
		Singleton4 s3=Singleton4.s1;  
		System.out.println(s2==s3);
	}
	
}
class Singleton4{
		//1.私有构造方法,其他类不能访问该类构造方法
		private Singleton4(){};
		static final Singleton4 s1=new Singleton4();
		
		
}

猜你喜欢

转载自blog.csdn.net/qq_42429369/article/details/84185280