这一则博客主要写的是单例设计模式,与实现多线程之间的通信等等~
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();
}
}