1.线程的概念

  • 程序 进程 线程

    • 程序:指令集 静态概念

    • 进程:操作系统调度程序 动态概念

    • 线程:在进程内多条执行路径

2.线程和进程的区别

区    别 进程 线程
根 本 区 别 作为资源分配的单位 调度和执行的单位
开销 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销 线程可以看成轻量级的进程,同一类线程共享代码和数据空间,每个线程由独立的运行栈和程序技术器(PC),线程切换的开销小
所处环境 在操作系统中能同时运行多个任务(程序) 在同一应用程序中有多个顺序流同时执行
分配内存 系统在运行的时候会为每个进程分配不同的内存区域 除了CPU之外,不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源
包含关系 没有线程的进程是可以被看做是单线程的,如果一个进程内拥有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的 线程是进程的一部分,所以线程有的时候被称为轻权进程或者轻量级进程

3.JAVA中实现多线程

  • 在Java中负责线程功能的是java.lang.Thread这个类

  • 可以通过常见Thread的实例来创建新的线程

  • 每个线程都是通过某个特定Thread对象所对应的run()方法来完成其操作的,run()方法称为线程体

  • 通过调用Thread对象的start()方法来启动一个线程

方法一:继承Thread类,重写run()方法,创建对象后调用start()方法

/**
 * 模拟龟兔赛跑
 * @author Matrix42
 *
 */
public class Rabbit extends Thread{

    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("兔子跑了"+i+"步");
        }
    }

}

class Tortoise extends Thread{

    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("乌龟跑了"+i+"步");
        }
    }

}
public class RabbitApp {

    public static void main(String[] args) {

        //创建子类对象
        Rabbit rabbit = new Rabbit();
        //调用start()方法
        rabbit.start();

        Tortoise tortoise = new Tortoise();
        tortoise.start();

    }

}

方法二:实现Runnable接口

  • 继承Thread类方式的缺点:如果我们的类已经从一个类继承,则无法再继承Thread类

  • 通过Runnable接口实现多线程的优点:可以同时实现继承.实现Runnable接口方式要通用一些

    • 避免单继承

    • 方便共享资源 同一份资源 多个代理访问

静态代理:

/**
 * 静态代理设计模式
 * 1.真实角色
 * 2.代理角色 持有真实角色的引用
 * 3.二者实现相同的接口
 * @author Matrix42
 *
 */
public class StaticProxy {

    public static void main(String[] args) {

        //创建真实角色
        You you = new You();

        //创建代理角色+真实角色的引用
        WeddingCompany weddingCompany = new WeddingCompany(you);

        //执行任务
        weddingCompany.marry();

    }

}

//接口
interface Marry{
    void marry();
}

//真实角色
class You implements Marry{

    @Override
    public void marry() {
        System.out.println("你和嫦娥结婚了...");
    }

}

//代理角色
class WeddingCompany implements Marry{

    private Marry you;

    public WeddingCompany(){

    }

    public WeddingCompany(Marry you) {
        this.you = you;
    }

    private void Before(){
        System.out.println("布置猪窝...");
    }

    private void After(){
        System.out.println("闹玉兔...");
    }

    @Override
    public void marry() {
        Before();
        you.marry();
        After();
    }

}

Demo:

/**
 * 使用Runnable创建线程
 * 1.类实现Runnable接口 重写run()方法
 * 2.启动多线程 使用静态代理
 *  1).创建真实角色
 *  2).创建代理角色
 *  3).调用.start()启动线程
 * @author Matrix42
 *
 */
public class Programmer implements Runnable{

    @Override
    public void run() {

        for(int i=0;i<1000;i++){
            System.out.println("一边敲helloworld....");
        }

    }

}
public class ProgrammerApp {

    public static void main(String[] args) {

        Programmer programmer = new Programmer();

        Thread proxy = new Thread(programmer);

        proxy.start();

        for(int i=0;i<1000;i++){
            System.out.println("一边聊QQ....");
        }

    }

}

方法三:通过Callable接口实现多线程(java.util.concurrent)[了解]

  • 优点:可以获取返回值

    Callable和Future接口

    Callable类似Runnable接口,实现Callable接口的类和实现Runnable的类都是可以被其他线程执行的任务

    Callable和Runnable有几点不同:

    • Callable规定的方法是call(),而Runnable规定的方法是run()

    • call()方法可以抛出异常,而run()方法不能抛出异常

    • Callable的任务执行后可返回值,运行Callable任务可拿到一个Future对象,而Runnable的任务是不能返回值的

Future表示异步计算的结果.它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果

通过Future对象可了解任务执行情况,可以取消任务的执行,还可以获取任务执行的结果

  • 缺点:繁琐

  • 思路:

    • 创建Callable实现类+重写call

    • 借助执行调度服务ExecutorService获取Future对象

      ExecutorService ser = Executors.newFixedThreadPool(2);

      Future result = ser.submit(实现类对象);

    • 获取值result.get();

    • 停止服务ser.shutdownNow();

Demo:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 使用Callable创建线程
 * @author Matrix42
 *
 */
public class Call {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        //创建线程
        ExecutorService ser = Executors.newFixedThreadPool(2);

        Race tortoise = new Race("乌龟",1000);

        Race rabbit = new Race("兔子",500);

        //获取值
        Future<Integer> result1 = ser.submit(tortoise);
        Future<Integer> result2 = ser.submit(rabbit);

        Thread.sleep(2000);
        tortoise.setFlag(false);
        rabbit.setFlag(false);

        int num1 = result1.get();
        int num2 = result2.get();

        System.out.println("乌龟跑了--->"+num1+"步");
        System.out.println("兔子跑了--->"+num2+"步");

        //停止线程
        ser.shutdownNow();

    }

}

//尖括号里的类型表示返回值类型  call()的返回值与它相同
class Race implements Callable<Integer>{

    private String name;
    private long time;
    private boolean flag = true;
    private int step = 0;//步

    Race(){

    }

    Race(String name){
        this.name = name;
    }

    Race(String name,long time){
        this.name = name;
        this.time = time;
    }

    @Override
    public Integer call() throws Exception {
        while(flag){
            Thread.sleep(time);
            step++;
        }
        return step;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getStep() {
        return step;
    }

    public void setStep(int step) {
        this.step = step;
    }

}

每个方法隐式的向外声明RuntimeException

4.线程的状态

                     <---阻塞状态<---  
                    |              |
创建---start()--->就绪状态<---->运行状态----->终止
  • 新生状态

    用new关键字和Thread类或其子类建立一个线程后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable)

  • 就绪状态

    处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列,等待系统为其分配CPU.等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为"CPU调度",一旦获得CPU,线程就进入运行状态并自动调用自己的run方法

  • 运行状态

    在运行状态的线程执行自己的run方法中的代码,知道调用其他方法而终止或等待某资源而阻塞或完成任务而死亡,如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态

  • 阻塞状态

    处于运行状态的线程在某些情况下,如执行了sleep方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态,在阻塞状态的线程不能进入就绪队列.只有当引起阻塞的原因消除时,如sleep时间已到,或等待的I/O设备空闲下来,线程变转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续执行.

  • 死亡状态

    死亡状态是线程生命周期中的最后一个阶段.线程死亡的原因有两个.一个是正常运行的线程完成了它全部工作;另一个是线程被强制性的终止,如通过执行stop或destory方法来终止一个线程[不推荐使用这两个方法,前者会产生异常,后者是强行终止,不会释放锁]

5.停止线程

  • 自然终止:线程体正常执行完毕

  • 外部干涉:

    • 线程类中定义线程体使用的标识

    • 线程体使用该标识

    • 提供对外的方法改变该标识

    • 外部根据条件调用该方法即可

Demo:

public class Demo {

    public static void main(String[] args) {

        Study s = new Study();
        new Thread(s).start();

        for(int i=0;i<100;i++){
            if(i==50){
                s.stop();
            }
            System.out.println("main...."+i);
        }

    }

}

class Study implements Runnable {

    private boolean flag = true;

    @Override
    public void run() {

        while(flag){
            System.out.println("study thread...");
        }

    }

    public void stop() {
        this.flag = false;
    }

}

6.线程阻塞

  • join:把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程

Demo:

public class JoinDemo extends Thread{

    public static void main(String[] args) throws InterruptedException {

        JoinDemo jDemo = new JoinDemo();
        jDemo.start();

        for(int i=0;i<1000;i++){
            if(50==i){
                jDemo.join();   //main阻塞
            }
            System.out.println("main..."+i);
        }

    }

    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("Thread....."+i);
        }
    }

}
  • yield:暂停当前线程(static方法)
public class YieldDemo extends Thread{

    public static void main(String[] args) throws InterruptedException {

        JoinDemo jDemo = new JoinDemo();
        jDemo.start();

        for(int i=0;i<1000;i++){
            if(i%20==0){
                Thread.yield();//暂停本线程
            }
            System.out.println("main..."+i);
        }

    }

    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("yield....."+i);
        }
    }

}
  • sleep:强制当前正在执行的线程休眠(静态方法),不释放锁

    用途:

    • 与时间相关,倒计时

    • 网络延时

Demo 01:

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 1.倒数10个数
 * 2.倒计时
 * @author Matrix42
 *
 */
public class SleepDemo {

    public static void main(String[] args) throws InterruptedException {

        test02();

    }

    public static void test01() throws InterruptedException{
        int num = 10;
        while(true){
            System.out.println(num--);
            Thread.sleep(1000); //暂停1秒
            if(num<=0){
                break;
            }
        }
    }

    public static void test02() throws InterruptedException{
        Date endTime = new Date(System.currentTimeMillis()+10*1000);
        long end = endTime.getTime();
        while(true){
            System.out.println(new SimpleDateFormat("mm:ss").format(endTime));
            endTime = new Date(endTime.getTime()-1000);
            Thread.sleep(1000);
            if(end-10000>endTime.getTime()){
                break;
            }
        }
    }

}

Demo 02:

/**
 * 模拟网络延时 线程不安全
 * @author Matrix42
 *
 */
public class SleepDemo02 {

    public static void main(String[] args) {
        Web12306 web = new Web12306();
        Thread t1 = new Thread(web,"路人甲");
        Thread t2 = new Thread(web,"黄牛乙");
        Thread t3 = new Thread(web,"攻城狮");

        t1.start();
        t2.start();
        t3.start();

    }

}

class Web12306 implements Runnable{

    private int num = 50;

    @Override
    public void run() {
        while(true){
            if(num<=0){
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        }

    }

}

会产生对同一个资源的并发问题:

黄牛乙抢到了3
攻城狮抢到了2
黄牛乙抢到了1
路人甲抢到了0
攻城狮抢到了-1

7.线程基本信息与优先级

方法 功能
isAlive() 判断线程是否还"活"着,即线程是否还未终止
getPriority() 获得线程的优先级数值
setPriority() 设置线程的优先级数值
setName() 给线程一个名字
getName() 取得线程的名字
currentThread() 取得当前正在运行的线程对象也就是取得自己本身

Demo:

public class MyThread implements Runnable{
    private boolean flag = true;
    private int num = 0;

    @Override
    public void run() {
        while(flag){
            System.out.println(Thread.currentThread().getName()+"-->"+num++);
        }

    }

    public void stop(){
        this.flag = false;
    }

}
public class InfoDemo {

    public static void main(String[] args) throws InterruptedException {

        MyThread it = new MyThread();
        Thread proxy = new Thread(it,"挨踢"); //如果不取名则自动编号Thread0....
        proxy.setName("IT");
        System.out.println(proxy.getName());
        System.out.println(Thread.currentThread().getName());
        proxy.start();
        System.out.println(proxy.isAlive());
        Thread.sleep(200);
        it.stop();  //不会马上停止
        Thread.sleep(100);
        System.out.println(proxy.isAlive());

    }

}
/**
 * 优先级不代表绝对的先后顺序,而是被执行的概率
 * MAX_PRIORITY 10
 * NORM_PRIORITY 5 默认
 * MIN_PRIORITY 1
 * @author Matrix42
 *
 */
public class InfoDemo02 {

    public static void main(String[] args) throws InterruptedException {

        MyThread it = new MyThread();
        Thread p1 = new Thread(it,"挨踢");
        MyThread it2 = new MyThread();
        Thread p2 = new Thread(it,"挨踢2");

        p1.setPriority(Thread.MAX_PRIORITY);
        p2.setPriority(Thread.MIN_PRIORITY);
        p1.start();
        p2.start();

        Thread.sleep(1000);
        it.stop();
        it2.stop();
    }

}

8.线程同步与锁定

  • 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问

  • 由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种方法:synchronized方法和synchronized块,synchronized块锁定的只能是引用类型|this|类.class

Demo:

/**
 * 模拟网络延时 线程安全但速度慢
 * @author Matrix42
 *
 */
public class SleepDemo02 {

    public static void main(String[] args) {
        Web12306 web = new Web12306();
        Thread t1 = new Thread(web,"路人甲");
        Thread t2 = new Thread(web,"黄牛乙");
        Thread t3 = new Thread(web,"攻城狮");

        t1.start();
        t2.start();
        t3.start();

    }

}

class Web12306 implements Runnable{

    private int num = 50;
    private boolean flag = true;

    @Override
    public void run() {
        while(flag){
            test1();
        }

    }

    public synchronized void test1(){
        if(num<=0){
            flag = false;
            return;
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
    } 

}

synchronized块:

    public void test1(){
        synchronized(this){
            if(num<=0){
                flag = false;
                return;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        } 
    }

单例设计模式:

public class SynDemo {

    public static void main(String[] args) {

        new JvmThread(100).start();
        new JvmThread(500).start();
        /*
         * 使用getInstance1
         * Thread-0-->创建:com.lorinda.thread.Jvm@854a9ed
         * Thread-1-->创建:com.lorinda.thread.Jvm@29e0f336
         * 使用getInstance2 效率不高
         * Thread-0-->创建:com.lorinda.thread.Jvm@29e0f336
         * Thread-1-->创建:com.lorinda.thread.Jvm@29e0f336
         * * 使用getInstance3 效率不高
         * Thread-1-->创建:com.lorinda.thread.Jvm@29568226
         * Thread-0-->创建:com.lorinda.thread.Jvm@29568226
         * */

    }

}

class JvmThread extends Thread{
    private long time;

    public JvmThread(){}

    public JvmThread(long time){
        this.time = time;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->创建:"+Jvm.getInstance(time));
    }
}

/**
 * 单例设计模式
 * 确保一个类只有一个对象
 * 懒汉式
 * 1.构造器私有化,避免外部直接创建对象
 * 2.声明一个私有化的静态变量
 * 3.创建一个对外的公共的静态方法访问该变量,如果变量没有对象,创建该对象
 * @author Matrix42
 *
 */
class Jvm{
    //声明一个私有的静态变量
    private static Jvm instance = null;

    //构造器私有化,避免外部直接创建对象
    private Jvm(){

    }

    //创建一个对外的公共的静态方法访问该变量,如果变量没有对象,创建该对象
    public static Jvm getInstance1(long time){
        if(null==instance){
            try {
                Thread.sleep(time);//延时,放大错误发生的概率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Jvm();
        }
        return instance;
    }

    //效率不高
    public static synchronized Jvm getInstance2(long time){
        if(null==instance){
            try {
                Thread.sleep(time);//延时,放大错误发生的概率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Jvm();
        }
        return instance;
    }

    //效率不高 存在对象也需要等待
    public static synchronized Jvm getInstance3(long time){
        synchronized (Jvm.class) {
            if(null==instance){
                try {
                    Thread.sleep(time);//延时,放大错误发生的概率
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                instance = new Jvm();
            }
        }
        return instance;
    }

    //提高效率  已经有对象了就不用等了
    //double checking
    public static synchronized Jvm getInstance4(long time){
        if(null==instance){    //提高效率
            synchronized (Jvm.class) {
                if(null==instance){    //安全
                    try {
                        Thread.sleep(time);//延时,放大错误发生的概率
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new Jvm();
                }
            }
        }
        return instance;
    }
}

饿汉式:

/**
 * 饿汉式
 * 1.构造器私有化
 * 2.声明私有的静态属性,同时创建该对象
 * 3.对外提供访问属性的静态方法
 * @author Matrix42
 *
 */
class Jvm2{
    private static Jvm2 instance = new Jvm2();

    private Jvm2(){}

    public static Jvm2 getInstance(){
        return instance;
    }
}

优化的饿汉式:

/**
 * 类在使用的时候才加载,延缓了加载时间
 * @author Matrix42
 *
 */
class Jvm3{
    private static class JVMholder{
        private static Jvm3 instance = new Jvm3();
    } 

    private Jvm3(){}

    public static Jvm3 getInstance(){
        return JVMholder.instance;
    }
}

Runtime类就用的单例模式(饿汉式)

9.死锁

过多的同步容易产生死锁,比如一手给钱一手给货,你不给钱我就不给货

public class SynDemo02 {

    public static void main(String[] args) {
        Object g = new Object();
        Object m = new Object();
        Test t1 = new Test(g,m);
        Test2 t2 = new Test2(g, m);
        Thread thread = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread.start();
        thread2.start();
    }
}

class Test implements Runnable{

    Object goods;
    Object money;

    public Test(Object goods, Object money) {
        super();
        this.goods = goods;
        this.money = money;
    }

    @Override
    public void run() {
       while(true){
           test();
       }

    }

    public void test(){
        synchronized (goods) {  //锁住goods还要money
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (money) {

            }
        }

        System.out.println("一手给钱..");
    }

}

class Test2 implements Runnable{

    Object goods;
    Object money;

    public Test2(Object goods, Object money) {
        super();
        this.goods = goods;
        this.money = money;
    }

    @Override
    public void run() {
       while(true){
           test();
       }

    }

    public void test(){
        synchronized (money) {  //锁住money还要goods
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (goods) {

            }
        }

        System.out.println("一手给货..");
    }

}

解决同步的方法:生产者消费者模式

10.生产者消费者模式_信号灯法

  • 生产者消费者问题(Producer-consumer problem),也称为有限缓存问题(Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线程---即所谓的"生产者"和消费者"在实际运行时会发生的问题.生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程.与此同时,消费者也在缓冲区消耗这些数据.该问题的关键就是要保证生产者不会再缓冲区满时加入数据,消费者也不会在缓冲区空时消耗数据

  • 要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据之后,再唤醒消费者.通常常用的方法有信号灯法,管程法等.如果解决方法不够完善,则容易出现死锁的情况.出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己

Demo:

/**
 * 一个场景,共同的资源
 * 生产者消费者模式信号灯法
 * wait()会释放锁,sleep()不释放锁
 * notify()/notifyAll()唤醒
 *与synchronized一起使用
 */
public class Movie {

    private String pic;

    //flag-->true 生产者生产,消费者等待,生产完成后通知消费
    //flag-->false 消费者消费,生产者等待,消费完后通知生产
    private boolean flag = true;

    /**
     * 播放
     */
    public synchronized void play(String pic){
        if(!flag){  //生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //开始生产
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("生产了:"+pic);
        //生产完毕
        this.pic = pic;
        //通知消费
        this.notify();
        //生产者停下
        this.flag=false;
    }

    public synchronized void watch(){
        if(flag){   //消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //开始消费
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //消费完毕
        System.out.println("消费了:"+pic);
        //通知生产
        this.notify();
        //停止消费
        this.flag=true;
    }

}
/**
 * 生产者
 * @author Matrix42
 *
 */
public class Player implements Runnable {

    private Movie m;

    public Player(Movie m) {
        super();
        this.m = m;
    }

    public void run() {

        for(int i=0;i<20;i++){
            if(i%2==0){
                m.play("左青龙");
            }else {
                m.play("右白虎");
            }
        }

    }

}
public class Watcher implements Runnable {

    private Movie m;

    public Watcher(Movie m) {
        super();
        this.m = m;
    }

    public void run() {

        for(int i=0;i<20;i++){
            m.watch();
        }

    }

}
public class App {

    public static void main(String[] args) {
        //共同的资源
        Movie m = new Movie();

        //多线程
        Player p = new Player(m);
        Watcher w = new Watcher(m);

        new Thread(p).start();
        new Thread(w).start();

    }

}

11.任务调度

  • Timer定时器类

  • TimerTask任务类

  • 通过java timer timertask:(spring的任务调度就是通过他们来实现的)在这种方式中,Timer类实现的是类似闹钟的功能,也就是定时或者每隔一定时间触发一次线程.其实,Timer类本身实现的就是一个线程,只是这个线程是用来实现调用其它线程的.二TimerTask类是一个抽象类,该类实现了Runnable接口,所以按照前面的介绍,该类具备多线程的能力.

  • 在这种实现方式中,通过继承TimerTask使该类获得多线程的能力,将需要多线程执行的代码写在run方法的内部,然后通过Timer类启动线程的执行.

  • 在实际使用时,一个Timer可以启动任意多个TimerTask实现的线程,但是多个线程之间会存在阻塞.所以如果多个线程之间需要完全独立运行的话,最好是一个Timer启动一个TimerTask

import java.util.Timer;
import java.util.TimerTask;

/**
 * schedule(TimerTask task,Date time) 定时执行一次
 * schedule(TimerTask task,Date time,long period) 每隔period执行一次
 * 了解,可以看看第三方框架quartz
 * @author Matrix42
 *
 */
public class TimeDemo1 {

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                System.out.println("so easy...");

            }
        }, 1000,200);

    }

}

12.总结

  • 一,创建线程

    • 1.继承Thread

    • 实现Runnable

    • 实现Callable(了解)

  • 二,线程的状态

      1. 新生-->start-->就绪-->运行-->阻塞-->终止
    • 2.终止线程

    • 3,阻塞 join yield sleep

  • 三,线程的信息

    • 1.Thread.currentThread

    • 2.获取名称 设置名称 设置优先级 判断状态

  • 四,同步:对同一份资源

    synchronized(引用类型变量|this|类.class){}

    修饰符 synchronized 方法名{
    }

    过多的同步可能会造成死锁

  • 五,生产者消费者模式

  • 六,任务调度

后期:juc,quartz 自学