Java学习笔记 - 多线程2
生产者&消费者模型
-
wait & notify 方法不是线程对象的方法,是普通java对象的都有的方法
-
wait & notify方法建立在线程同步的基础之上。因为多线程要同时操作一个对象,有线程安全问题
-
wait(): o.wait()让正在o对象上活动的线程t进入等待状态,并且释放掉之前占有对象o的锁
-
notify(): o.notify()让正在o对象上等待的线程唤醒,只是通知,不会释放掉之前占有对象o的锁
示例程序:
public class ProducerAndConsumer {
public static void main(String[] args) {
List list = new ArrayList();
Producer pro = new Producer(list);
Consumer con = new Consumer(list);
pro.setName("生产者进程");
con.setName("消费者进程");
pro.start();
con.start();
}
}
//生产者线程类
class Producer extends Thread{
private List list;
public Producer(List list){
this.list = list;
}
@Override
public void run() {
//一直生产
while (true){
synchronized (list){
if(list.size() > 0){
try {
//当前线程进入等待状态,并且释放Producer之前占有的list的锁
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序能执行到这里说明仓库是空的,可以生产
Object obj = new Object();
list.add(obj);
System.out.println(Thread.currentThread().getName() + "-->" + obj);
//唤醒消费者进行消费:唤醒list对象上正在等待的线程,但不会释放之前占有的list的锁
list.notify();
}
}
}
}
//消费者线程类
class Consumer extends Thread{
private List list;
public Consumer(List list){
this.list = list;
}
@Override
public void run() {
while (true){
synchronized (list){
if(list.size() == 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序能执行到这里说明仓库是满的,可以消费
Object obj = list.remove(0);
System.out.println(Thread.currentThread().getName() + "-->" + obj);
//唤醒生产者进行生产:唤醒list对象上正在等待的线程,但不会释放之前占有的list的锁
list.notify();
}
}
}
}
守护线程
- 守护线程:后台线程,例如垃圾回收线程
- 特点:一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束
- 方法:final void setDaemon(boolean on) true表示设置调用线程为守护线程
示例程序:
public class ProtectedThreadTest {
public static void main(String[] args) {
BakDataThread bdt = new BakDataThread();
//设置线程为守护线程,所有的用户线程都结束,守护线程会自动结束
bdt.setDaemon(true);
bdt.start();
for (int i = 0; i < 5; i++) {
System.out.println("主线程运行 ---》》" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class BakDataThread extends Thread{
@Override
//方法覆盖不能比之前的方法抛出更多的异常,所以只能采用try catch的处理方式
public void run() {
int i = 0;
while (true){
System.out.println("守护线程运行---》》" + i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
定时器
- 作用:间隔特定的时间,执行特定的程序
- 在java的类库中已经写好了一个定时器:java.util.Timer
实现步骤
- 1.创建定时器
public Timer(boolean isDaemon)
- 2.调用schedule方法:
void schedule(TimerTask task, Date firstTime, long period)
参数:抽象类TimerTask; 第一次的执行时刻; 执行间隔时间/毫秒
示例代码
public class TimerTest {
public static void main(String[] args) throws ParseException {
//创建定时器
Timer timer = new Timer();
//Timer timer = new Timer(true); //true:表示作为一个守护线程运行
//指定起始执行时刻
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date firstTime = sdf.parse("2020-05-31 13:08:10");
//第一种方式:使用匿名内部类的方式,实现抽象类TimerTask
//从firstTime开始,每period毫秒执行一次run()方法
timer.schedule(new TimerTask() {
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(new Date());
System.out.println(strTime + " : 完成了一次数据备份");
}
},firstTime,1000 * 10);
}
}
// 第二种方法:编写定时任务类,实现抽象类TimerTask
class LogTimerTask extends TimerTask {
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(new Date());
System.out.println(strTime + " : 完成了一次数据备份");
}
}