原文链接:https://blog.csdn.net/weixin_42032770/article/details/107536554?utm_medium=distribute.pc_category.none-task-blog-hot-3.nonecase&depth_1-utm_source=distribute.pc_category.none-task-blog-hot-3.nonecase&request_id=#4.1%E3%80%81%E5%B8%B8%E8%A7%81%E7%9A%84%E7%BA%BF%E7%A8%8B%E8%B0%83%E5%BA%A6%E6%A8%A1%E5%9E%8B

5、定时任务

5.1、实现一个定时器

package Thread;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
    public static void main(String[] args) throws ParseException {
        //创建定时器对象
        Timer timer = new Timer();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date firstTime = sdf.parse("2020-07-25 19:10:30");
        //指定定时任务
        //timer.schedule(定时任务,第一次执行时间时间,间隔多久执行一次)
        timer.schedule(new LogTimerTask(), firstTime, 1000 * 5);
    }
}

//编写一个定时任务
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 + ":成功完成了一次数据备份!");
    }
}

java线程基础知识整理(下)_第1张图片

6、通过Callable接口实现一个线程

使用Callable接口实现线程,可以获得该线程的返回值(JDK8新特性)

一个简单的实例:

package Thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThirdWay {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask(new Task());
        Thread thread = new Thread(futureTask);
        thread.start();
        Object object = futureTask.get();  //通过get方法可以获取当前线程的返回值
        ////主线程中这里的程序必须等待get()方法结束才执行
        // get()方法为了拿另一个线程的执行结果需要等待其执行完成,因此要等待较长时间
        System.out.print("线程执行结果:");
        System.out.println(object);
    }
}

class Task implements Callable {

    @Override
    public Object call() throws Exception {
        System.out.println("call method begin");
        Thread.sleep(1000 * 10);
        System.out.println("call method end");
        int a = 100;
        int b = 200;
        return a + b;
    }
}

java线程基础知识整理(下)_第2张图片

FutureTask类相关源码
public FutureTask(Callable callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

Future类中实现了get方法获取传入线程的返回结果

7、Object类中的wait和notify方法

7.1、wait和notify方法介绍

wait和notify方法不是线程对象的方法,不能通过线程对象调用。

Object object=new Object();
object.wait();//object.wait()让正在object对象上活动的线程进入等待状态,无限等待,直到被唤醒为止
object.notify();//object.notify()唤醒正在object对象上等待的线程
object.notifyAll();//object.notifyAll唤醒正在object对象上等待的所有线程

java线程基础知识整理(下)_第3张图片

一个简单的生产者和消费者实例

模拟生产者生产一个,消费者就消费一个。让仓库始终零库存。

package Thread;

import java.awt.*;
import java.util.*;
import java.util.List;

public class Producer_Consumer {
    public static void main(String[] args) {
        List list = new ArrayList();
        Thread thread1 = new Thread(new Consumer(list), "消费者线程");
        Thread thread2 = new Thread(new Producer(list), "生产者线程");
        thread1.start();
        thread2.start();
    }
}

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

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

    @Override
    public void run() {
        //消费
        while (true) {
            synchronized (list) {
                //如果仓库已经空了,消费者线程等待并释放list集合的锁
                if (list.size() == 0) {
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //仓库中有商品,消费者进行消费
                String str = list.remove(0);
                System.out.println(Thread.currentThread().getName() + " 消费 " + str);
                list.notify();  //唤醒生产者
            }

        }
    }
}

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

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

    @Override
    public void run() {
        //生产
        while (true) {
            synchronized (list) {
                //如果仓库里有东西,则停止生产。生产者线程等待并释放list集合的锁
                if (list.size() > 0) {  
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                list.add("商品");
                System.out.println(Thread.currentThread().getName() + " 生产 " + list.get(0));
                list.notify();  //唤醒消费者
            }
        }
    }
}

java线程基础知识整理(下)_第4张图片

7.3、实现奇偶数的交替输出

package Thread;

/**
 * 使用生产者和消费者模式实现两个线程交替输出:一个线程负责输出奇数,另一个线程负责输出偶数
 */
public class Number {
    public static void main(String[] args) throws InterruptedException {
        Num num = new Num(0);
        Thread thread1 = new Thread(new Odd(num), "Odd");
        Thread thread2 = new Thread(new Event(num), "Event");
        thread1.start();
        thread2.start();
    }
}

class Odd implements Runnable {
    Num num;

    public Odd(Num num) {
        this.num = num;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (num) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (num.getI() % 2 == 0) {
                    try {
                        num.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "--->" + num.printNum());
                num.notifyAll();
            }
        }
    }
}

class Event implements Runnable {
    Num num;

    public Event(Num num) {
        this.num = num;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (num) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (num.getI() % 2 != 0) {
                    try {
                        num.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "--->" + num.printNum());
                num.notifyAll();
            }
        }
    }
}

class Num {
    private int i = 0;

    public Num(int i) {
        this.i = i;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    int printNum() {
        return i++;
    }
}

java线程基础知识整理(下)_第5张图片

点击下方链接免费获取Android进阶资料:
https://shimo.im/docs/tXXKHgdjPYj6WT8d/