Java——多线程基本使用(三) 饿汉式和懒汉式的单例设计模式,多线程之间的通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zoweiccc/article/details/83018595

这一则博客主要写的是单例设计模式,与实现多线程之间的通信等等~

1.单例设计模式:保证类在内存中只有一个对象

2.保证类在内存中只有一个对象

             (1)控制类的创建,不让其他类来创建本类的对象。用private私有构建函数

             (2)在本类中定义一个本类的对象。

             (3)提供公共的访问形式

3.单例写法

             (1)饿汉式

             (2)懒汉式

             (3)直接用final修饰 (private static final Single3 s=new Single3();)

             饿汉式与懒汉式的区别:

             (1)饿汉式是空间换时间,懒汉式是时间换空间

             (2)在多线程访问时,饿汉式不会创建多个对象,懒汉式有可能会创建多个对象

4.Runtime类:使用了单例设计模式,是一个单例类

5.Timer类(计时器):一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行

             schedule(TimeTask task,Date time),安排在指定的时间执行指定的任务

t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50),3000);  安排指定任务在指定时间开始进行重复的固定延迟执行

第一个参数是安排的任务,第二个参数是执行时间,第三个参数是过多长时间再重复执行

6.两个线程间的通信

             什么时候需要通信?

             在多个线程并发执行时,在默认情况下cpu是随机切换线程的;如果我们希望它们有规律的执行,就可以使用通信,例如每一次线程执行一次打印

             如何进行通信?

             如果希望线程等待,就调用wait();如果希望唤醒等待的线程,就调用notify();这两个方法必须再同步代码中执行,并且使用同步锁对象来调用

             wait(),notify()和notifyAll()方法

7.三个或三个以上间的线程通信

             (1)notify()方法是随机唤醒一个线程

             (2)notifyAll()方法是唤醒所有线程

        如果多个线程之间通信,需要使用notifyAll()通知所有线程,用while来反复判断条件

8.线程之间通信需要注意的问题

             (1)在同步代码块中,用哪个对象锁就用哪个对象调用wait()方法

             (2)因为锁对象可以是任意对象,且Object类是所有类的基类所有将wait()和notify()方法定义在Object类中

             (3)sleep方法和wait方法的区别

                    1)sleep方法必须传入参数,参数是时间,时间道理自动醒来;wait方法可以传入参数,在参数的时间结束后等待,                      不传入参数就是直接等待

                    2)sleep方法在同步函数或同步代码块中不释放锁;wait方法在同步函数或者同步代码块中,释放锁

9.互斥锁

             (1)同步:使用ReentrantLock类的lock()和unlock()方法进行同步

             (2)通信

                    1)使用ReentrantLock类的newCondition()方法可以获取Condition对象(使用await与signal方法)

                    2)需要等待的时候使用Condition的await()方法,唤醒的时候使用signal()方法

                    3)不同的线程使用不同的Condition,这样就能区分唤醒的时候找哪个线程

 

 

在运行下面测试代码中,可以一个案例一个案例运行,因为会有可能会出一些问题,比如说前面的死循环无法运行下一个例子要实现的函数等等....

package pra_21;
import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class J_40 {

	/**
	 * @param args
	 * @throws IOException 
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws IOException, InterruptedException {
		/*
		//1.单例设计模式
		//Single s1=new Single();
		//Single s2=Single.s;			//成员变量被私有,不能通过类名点去调用,解决了调用改变类的成员变量s
		Single s3=Single.getS();
		Single s4=Single.getS();		//此时不能修改
		System.out.println(s3==s4);
		
		//2.Runtime类
		Runtime rt=Runtime.getRuntime();		//获取运行是对象
		//在单独的进程中执行指定的字符串命令
		//rt.exec("shutdown -s -t 300"); 										
		//rt.exec("shutdown -a");
		
		//3.Timer类
		
		Timer t=new Timer();		//创建计时器
		t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50));//安排指定时间执行指定任务
			//第一个参数是安排的任务,第二个参数是执行时间,第三个参数是过多长时间再重复执行
		//t.schedule(new MyTimerTask(), new Date(118,9,11,18,52,50),3000);//安排指定任务在指定时间开始进行重复的固定延迟执行
		while(true){
			Thread.sleep(1000);
			System.out.println(new Date());
		}
		*/
		//4.两个线程之间的通信
			//等待唤醒机制
		final Pr2 p2=new Pr2();
		new Thread(){
			public void run(){
				while(true){
					try {
						p2.pri();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p2.pri2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		//5.多个线程之间的通信
		final Pr3 p3=new Pr3();
		new Thread(){
			public void run(){
				while(true){
					try {
						p3.pri();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p3.pri2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						p3.pri3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		//9.互斥锁
		final Pr3 pr4=new Pr3();
		new Thread(){
			public void run(){
				while(true){
					try {
						pr4.pri();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						pr4.pri2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		new Thread(){
			public void run(){
				while(true){
					try {
						pr4.pri3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();

	}
}
//饿汉式写法,看法常用
class Single{
	//1.私有构造方法,其他类不能访问该构造方法
	private Single(){}
	//2.创建本类对象
	private static Single s=new Single();	//如果是非静态的成员变量就只能用对象名点去调用,加了静态以后可以用类名点,但是被私有就不行
	//3.对外提供公告的访问方法(get set方法),主要是不让其改变s的值
	public static Single getS(){					//获取对象(实例)
		return s;
	}
}
//懒汉式,单例的延迟加载模式,会出现多线程不安全的问题
class Single2{
	//1.私有构造方法,其他类不能访问该构造方法
	private Single2(){}
	//2.声明引用
	private static Single2 s;	//
	//3.对外提供公告的访问方法(get set方法)
	public static Single2 getS(){					//获取对象(实例)
		if(s==null){
			s=new Single2();
		}
		return s;
	}
}
//第三种
class Single3{
	//1.私有构造方法,其他类不能访问该构造方法
	private Single3(){}
	//2.声明引用
	private static final Single3 s=new Single3();	//直接用final修饰,使其不能不改变
}
//Timer
class MyTimerTask extends TimerTask{

	@Override
	public void run() {
		System.out.println("走你!");
	}

}
//等待唤醒机制:两个方法 wait(),notify()方法,notifyAll()方法
class Pr2{
	private int flag=1;
	public void pri() throws InterruptedException{
		synchronized(this){
			if(flag!=1){
				this.wait();			//当前线程等待
			}
			System.out.print("p");
			System.out.print("q");
			System.out.print("r");
			System.out.print("s");
			System.out.print("1");
			System.out.println();
			flag=2;
			this.notify(); 				//随机唤醒单个等待线程
		}		
	}
	public void pri2() throws InterruptedException{
		synchronized(this){
			if(flag!=2){
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("2");
			System.out.println();
			flag=1;
			this.notify();
		}
	}
}
//多个线程
class Pr3{
	private int flag=1;
	public void pri() throws InterruptedException{
		synchronized(this){
			while(flag!=1){
				this.wait();			//当前线程等待
			}
			System.out.print("p");
			System.out.print("q");
			System.out.print("r");
			System.out.print("s");
			System.out.print("1");
			System.out.println();
			flag=2;
			this.notifyAll(); 				//随机唤醒单个等待线程
		}		
	}
	public void pri2() throws InterruptedException{
		synchronized(this){
			while(flag!=2){
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("2");
			System.out.println();
			flag=3;
			this.notifyAll();
		}
	}
	public void pri3() throws InterruptedException{
		synchronized(this){
			while(flag!=3){
				this.wait();			//线程3再此等待,if语句是在哪里等待,就在哪里起来,while则可以
										//while循环是循环判断,每一次都会判断标记
			}
			System.out.print("u");
			System.out.print("i");
			System.out.print("o");
			System.out.print("p");
			System.out.print("3");
			System.out.println();
			flag=1;
			this.notifyAll();
		}
	}
}
//使用互斥锁实现多线程
class Pr4{
	private ReentrantLock r=new ReentrantLock();
	private Condition c1=r.newCondition();
	private Condition c2=r.newCondition();
	private Condition c3=r.newCondition();
	private int flag=1;
	public void pri() throws InterruptedException{
			r.lock();					//获取锁
			if(flag!=1){
				c1.await();			//当前线程等待
			}
			System.out.print("p");
			System.out.print("q");
			System.out.print("r");
			System.out.print("s");
			System.out.print("1");
			System.out.println();
			flag=2;
			c2.signal();
			r.unlock();				//释放锁
		}		
	public void pri2() throws InterruptedException{
			r.lock();
			if(flag!=2){
				c2.await();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("2");
			System.out.println();
			flag=3;
			c3.signal();
			r.unlock();	
		}
	public void pri3() throws InterruptedException{
			r.lock();
			if(flag!=3){
				c3.await();
			}
			System.out.print("u");
			System.out.print("i");
			System.out.print("o");
			System.out.print("p");
			System.out.print("3");
			System.out.println();
			flag=1;
			c1.signal();
			r.unlock();
	}
}

猜你喜欢

转载自blog.csdn.net/zoweiccc/article/details/83018595