java基础 day15守护线程,定时器,实现线程的第三种方式FutureTask接口,生产者消费者模式(wait方法和notify方法)

守护线程

  • java语言中分为两大类,一类是用户线程,一类是守护线程(后台线程),其中最具代表的就是垃圾回收线程。
  • 特点:一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束。
  • 注意:主线程main是一个用户线程
  • 守护线程用在什么地方?
  • 每天零点的时候系统数据自动备份,需要用到定时器,并且我们可以将定时器设置成守护线程,一直在那看着,每到零点的时候自动备份一次,所有的用户线程结束的时候,守护线程自动退出,没有必要进行数据备份了。

示例:setDaemon()

package threadSafe;

/**
 * 守护线程
 *
 */
public class ThreadTest01 {
	public static void main(String[] args) {
		Thread t1 = new BakDataThread();
		t1.setName("备份数据线程");
		//启动线程之前,将线程设置为守护线程
		t1.setDaemon(true);
		t1.start();

		// 主线程:主线程是用户线程
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "--->" + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}
}

//数据备份
class BakDataThread extends Thread {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		int i = 0;
		while (true) {
			System.out.println(Thread.currentThread().getName() + "--->" + (++i));
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

定时器

  • 作用:间隔特定的时间,执行特定程序
  • 例如:每周要进行银行账户的总账操作,每天要进行数据的备份操作。
  • 在实际的开发中,每隔多久执行一段特定的程序,这种需求是很常见的,可以实现定时的方法有:
  • 可以使用sleep方法,睡眠,设置睡眠时间,没到这个时间点醒来,执行任务。这种方式是最原始的定时器
  • 利用java中已经写好的定时器:java.util.Timer,可以直接用。不过这种方式在实际开发中也很少用,因为很多高级的框架都支持定时服务。
  • 在实际的开发中,目前使用较多的是Spring框架中提供的SpringTask框架,这个框架只要进行简单的配置,就可以完成定时器的任务。

实现定时器:

package threadSafe;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.xml.crypto.Data;

/**
 * 实现定时器
 *
 */
public class ImplementTimer {
	public static void main(String[] args) throws ParseException {
		Timer timer = new Timer();
		// 守护线程的方式
		// Timer timer = new Timer(true);

		// 指定定时任务
		// timer.schedule(定时任务,第一次执行时间,间隔多久执行一次);
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date firstTime = simpleDateFormat.parse("2022-03-27 20:36:00");
		// 十秒完成一次数据备份
		timer.schedule(new LogTimertask(), firstTime, 1000 * 10);
	}
}

//编写一个定时任务类,假设这是一个记录日志的定时任务类
class LogTimertask extends TimerTask {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		// 编写你需要执行的任务就行了
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String strTime = simpleDateFormat.format(new Date());

		System.out.println(strTime + " : 成功完成一次数据备份");
	}

}

实现线程的第三种方式:实现Callable接口( JDK8新特性。)

  • 这种方式实现的线程可以获取线程的返回值。之前讲解的那两种方式是无法获取线程返回值的,因为run方法返回void.

示例:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
//JUC包下的,属于java的并发包,
import java.util.concurrent.FutureTask;

/**
 * 实现线程的第三种方式,实现Callable接口
 * 优点:可以获取到线程的执行结果
 * 缺点:在获取thread线程执行结果时,当前线程受到阻塞,效率较低
 *
 */
public class CreateThread {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 创建一个“未来任务类”对象,,参数非常重要,需要给一个Callable接口的实现类对象
		@SuppressWarnings("unchecked")
		FutureTask task = new FutureTask(new Callable() {

			@Override
			// call方法就相当于run方法,只不过这个有返回值
			public Object call() throws Exception {
				// TODO Auto-generated method stub
				// 模拟执行
				System.out.println("call mothod begin!");
				Thread.sleep(1000 * 5);
				System.out.println("call mothod end!");
				int a = 100;
				int b = 200;
				return a + b;
			}
		});
		// 创建线程对象
		Thread thread = new Thread(task);
		thread.start();

		// 这里是main方法,这是在主线程中,在主线程中,怎么获取thread的返回执行结果
		Object object = task.get();
		System.out.println("线程执行结果:" + object);
		// 这个get方法的执行会不会导致主线程阻塞?
		// 会,main方法执行需要等待get方法执行结束,而get方法为了另一个线程执行
		System.out.println("主线程执行结束!");
	}
}

关于Object类中的wait方法和notify方法(生产者消费者模式)

  • 第一: wai t和notifty方法不是线程对象的方法,是java中任何一个java对象都有的方法,因为这两个方式是object类中自带的。wait方法和notify方法不是通过线程对象调用。
    在这里插入图片描述
  • wait()方法作用
  • Objeat o = new Objeot() ; o. wait() ;
    表示:让正在o对象上活动的线程进入等待状态,无期限等待,直到被唤醒为止。o.wait() ;方法的调用,会让"当前线程(正在o对象上活动的线程) "进入等待状态。
  • notify()方法作用
  • Objeat o = new Objeot() ; o. notify() ;
  • 表示:唤醒正在o对象上等待的线程。
  • notifyAll()方法:唤醒o对象上处于等待的所有进程。
  • 生产者消费者模式
    在这里插入图片描述

实现生产者消费者模式

package threadSafe;

import java.util.ArrayList;
import java.util.List;

/*
1、使用wait方法和notify方法实现“生产者和消费者模式”
2.什么是“生产者和消费者模式”?
生产线程负责生产,消费线程负责消费。
生产线程和消费线程要达到均衡。
这是一种特殊的业务需求 ,在这种特殊的情况下需要使用wait方法和notify方法。
3. wait称notify方法不是线程对象的方法,是普通java对象都有的方法。
4. wait方法和notify方法建立在线程同步的基础之上。因为多线程要同时操作-一个仓库。 有线程安全问题。
5. wait方法作用:o.wait()让正在o对象上活动的线程t进入等待状态,并且释放掉t线程之前占有的o对象的锁。
6、notify方法作用: o.notify()让正在o对象上等待的线程唤醒,只是通知,不会释放o对象上之前占有的锁。
7、模拟这样一个需求:
仓库为list集合,list集合中只能存储一个元素,1个元素即为满,0个元素即为空
保证list元素永远最多存储一个元素,生产一个就必须消费一个
 */
public class ThreadTest02 {
	public static void main(String[] args) {
		List list = new ArrayList();
		// 创建生产者线程和消费者线程
		Thread t1 = new Thread(new Producer(list));
		Thread t2 = new Thread(new Consumer(list));
		t1.setName("生产者线程");
		t2.setName("消费者线程");
		t1.start();
		t2.start();
	}
}

//生产线程
class Producer implements Runnable {
	// 仓库
	private List list;

	public Producer(List list) {
		super();
		this.list = list;
	}

	@Override
	// 一直生产,死循环模拟一直生产
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			// 给仓库list加锁
			synchronized (list) {
				if (list.size() > 0) {
					// 当前线程进入等待状态,并且释放list集合的锁
					try {
						list.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				//程序能到这里说明可以生产
				Object obj = new Object();
				list.add(obj);
				System.out.println(Thread.currentThread().getName()+"--->"+obj);
				//唤醒消费者进程进行消费
				list.notify();
			}
		}
	}
}

//消费线程
class Consumer implements Runnable {
	private List list;

	public Consumer(List list) {
		super();
		this.list = list;
	}

	@Override
	// 一直消费
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (list) {
				if(list.size()== 0) {
					try {
						list.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				//程序能够执行到这里说明可以消费
				Object obj = list.remove(0);
				System.out.println(Thread.currentThread().getName()+"--->"+obj);
				//唤醒生产者进行生产
				list.notify();
			}			
		}

	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值