在劫

吾生也有涯,而知也无涯 。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

多线程的概述
    进程:
          正在运行的程序,是系统进行资源分配和调用的独立单位
          每一个进程都有它自己的内存空间和系统资源
    线程:
          进程中的单个顺序控制流,是一条执行路径
          一个进程如果只有一条执行路径,则成为单线程程序
          一个进程如果有多条执行路径,则成为多线程程序。
          一个进程内可以执行多个任务,则每个任务是一个线程。
    多进程有什么意义?
          单进程计算机只能做一件事,现在的计算机同一时间段内可以执行多个任务,提高CPU的使用率。
    多线程有什么意义?
          多线程的存在,不是提高程序的执行速度,其实是为了提高应用程序的使用率。
          程序执行其实就是抢CPU的资源,CPU的执行权。
          多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到。
          无法保证线程在哪个时刻抢到资源,线程执行有随机性。

并发:逻辑上同时发生,指在某个时间内同时运行多个程序。
并行:物理上同时发生,指在某个时间点运行多个程序。、
Java程序运行原理
    java命令启动java虚拟机,启动JVM,等于启动一个应用程序,也就是启动一个进程。
    该进程会自动启动一个主线程,然后主线程去调用某个类的main方法,所以main方法运行在主线程中,
    再次之前程序都是单线程的。
    JVM是多线程,垃圾回收线程也要先东西,否则会很容易出现内存溢出。
    最少启动了主线程和垃圾回收线程两个线程。

  由于线程是依赖进程存在的,所以我们应该先调用一个进程。进程是由系统创建的,所以我们应该调用系统功能创建一个进程。
  Java是不能调用系统功能的,所以我们没办法直接实现多线程程序。Java可以调用C/C++写好的程序实现多线程,由C/C++调用系统功能创建进程,然后由Java去调用这样的东西,然后提供一些类供我们使用,我们就可以实现多线程程序了。
  Java提供的类:Thread(线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。)
两种方式实现多线程程序:
  1、一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例

//继承Thread类实现多线程
public class ThreadTest extends Thread{
    public void run(){
        for(int i = 0; i < 20; i++){
            System.out.println(new Thread().getName() + "---" + i);
        }
    }
    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        t.start();
    }
}

  2、声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动

//实现Runnable接口实现多线程
public class RunableDemo implements Runnable{
    public static void main(String[] args) {
        //创建实现接口类对象
        RunableDemo rd = new RunableDemo();
        //把对象传入Thread类中
        Thread t = new Thread(rd);
        t.start();
    }
    public void run() {
        for(int i = 0; i < 10; i++){
            //Runnable接口只能通过Thread.currentThread().getName()获取名称
            //currentThread()方法返回的是一个Thread类 System.out.println(
Thread.currentThread().getName() + "---" + i); } } }
public class ThreadTest extends Thread{
    public void run(){
        for(int i = 0; i < 20; i++){
            //继承Thread类不需要使用new Thread().getName(),直接调用getName()方法就可以
            System.out.println(getName() + "---" + i);
        }
    }
    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        t.setName("线程");
        t.start();
    }
}

设置线程名

public class ThreadTest extends Thread{
    public ThreadTest(){}
    //调用父类的构造方法,才能在new对象的时候直接设置线程名
    public ThreadTest(String name) {
        super(name);
    }

    public void run(){
        for(int i = 0; i < 20; i++){
            System.out.println(getName() + "---" + i);
        }
    }
}
//-----------------------------------------------------------------
public class Demo {
    public static void main(String[] args) {
        //类中必须实现父类的构造方法,才能在创建对象的时候给线程设置名称
        ThreadTest tt = new ThreadTest("线程");
        tt.start();
    }

}

  但是上面方式无法获取main方法所在线程的名称,这种时候调用Thread的currentThread方法,返回一个Thread类。

    //static Thread currentThread() 返回对当前正在执行的线程对象的引用。 
    public void run(){
        for(int i = 0; i < 20; i++){
            System.out.println(Thread.currentThread().getName() + "---" + i);
            //System.out.println(getName() + "---" + i);
        }

线程有两种调度模型:
    1、分时调度模型,所有线程轮流使用CPU的使用权,平均每个线程占用CPU的时间片
    2、抢占式调度模型,优先让优先级高的线程使用CPU,如果线程优先级相同,随机选一个。优先级高的线程抢到的时间片多一些。
    Java使用的是抢占式的调度模型,设置获取线程的优先级:

public class ThreadTest extends Thread{
    public ThreadTest() {
    }

    public ThreadTest(String name) {
        super(name);
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            // 获取对象优先级,默认优先级是5.
            System.out.println(Thread.currentThread().getName() + "---"
                    + "getPriority()" + "---" + getPriority());
        }
    }
}
//----------------------------------------------------------------------
        ThreadTest tt = new ThreadTest("线程");
        ThreadTest tt2 = new ThreadTest("线程2");
        //void setPriority(int newPriority) 更改线程的优先级。 
        //优先级的范围:1 —— 10之间
        tt.setPriority(10);
        tt2.setPriority(1);
        tt.start();
        tt2.start();

线程睡眠

import java.util.Date;

public class ThreadSleep extends Thread{
    public ThreadSleep() {}
    public ThreadSleep(String name){
        super(name);
    }
    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + i + "___日期:" + new Date() );
            //sleep
            /*static void sleep(long millis) 
              在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 
              static void sleep(long millis, int nanos) 
              在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 */
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
//----------------------------------------------------------------------
public class Demo {
    public static void main(String[] args) {
        ThreadSleep ts1 = new ThreadSleep();
        ThreadSleep ts2 = new ThreadSleep();
        ThreadSleep ts3 = new ThreadSleep();
        ts1.setName("线程1");
        ts2.setName("线程2");
        ts3.setName("线程3");
        ts1.start();
        ts2.start();
        ts3.start();    
    }
}

线程加入

public class ThreadJoin extends Thread {
    public ThreadJoin() {
    }

    public ThreadJoin(String name) {
        super(name);
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}
//-------------------------------------------------------------------------
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        ThreadJoin ts1 = new ThreadJoin();
        ThreadJoin ts2 = new ThreadJoin();
        ThreadJoin ts3 = new ThreadJoin();
        ts1.setName("线程1");
        ts2.setName("线程2");
        ts3.setName("线程3");
        ts1.start();
        /*            void join(long millis) 
        等待该线程终止的时间最长为 millis 毫秒。 
        void join(long millis, int nanos) 
        等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 */
        //必须放在start()方法之后,表示这个线程走完了,其他线程才能执行
        ts1.join();
        ts2.start();
        ts3.start();    
    }
}

线程礼让

public class ThreadYield extends Thread {
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(getName() + "---" + i);
            /*
             * static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
             */
            // 让多个线程的执行更和谐,但不能靠它保证一个线程一次
            Thread.yield();
        }
    }
}
//------------------------------------------------------------------------
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        ThreadYield ty1 = new ThreadYield();
        ThreadYield ty2 = new ThreadYield();
        ty1.setName("线程1");
        ty2.setName("线程2");
        ty1.start();
        ty2.start();
    }
}

后台线程

public class ThreadDaemon extends Thread {
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
//---------------------------------------------------------------
/*setDaemon
        public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 
        该方法必须在启动线程前调用。
*/

public class Demo {
    public static void main(String[] args) throws InterruptedException {
/*        后台线程
        public final void setDaemon(boolean on);*/
        ThreadDaemon td1 = new ThreadDaemon();
        ThreadDaemon td2 = new ThreadDaemon();
        
        td1.setName("线程1");
        td2.setName("线程2");
        //设置守护线程
        td1.setDaemon(true);
        td2.setDaemon(true);
        
        td1.start();
        td2.start();
        
        //主线程死掉,守护线程也会死掉
        Thread.currentThread().setName("main线程");
        for(int i = 0; i < 5; i++){
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}

线程终止

import java.util.Date;

public class ThreadStop extends Thread {
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("开始执行:" + "---" + new Date());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("线程被终止");
            }
            System.out.println("线程终止时间:" + new Date());
        }
    }
}
//--------------------------------------------------------------------
/*中断线程
        public final void stop();已过时。 该方法具有固有的不安全性
        public void interrupt();中断线程,把线程的状态终止
        static boolean interrupted() 
          测试当前线程是否已经中断。 

*/
public class Demo {
    public static void main(String[] args) {
        ThreadStop ts1 = new ThreadStop();
        ts1.start();
        try {
            Thread.sleep(1000);
            ts1.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

线程生命周期
  新建:创建线程对象
  就绪:线程有执行的资格,没有执行权
  运行:有执行资格,有执行权
  阻塞:由于一些操作,让线程处于该状态,没有执行资格,没有执行权而另一些操作可以把它给激活,激活后处于就绪状态
  死亡:线程对象编程垃圾,等待被回收

实现Runnable买票的问题

public class RunableDemo implements Runnable{
    private int i = 100;
    public void run() {
        while(i > 0){
            System.out.println(Thread.currentThread().getName() + "---" + (i--));
            //i--;
        }
    }
}
//------------------------------------------------------------------------
public class Demo {
    public static void main(String[] args) {
        RunableDemo rd = new RunableDemo();
        Thread t1 = new Thread(rd);
        Thread t2 = new Thread(rd);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();

    }
}

  延迟就出错了

public class RunableDemo implements Runnable{
    private int i = 100;
    public void run() {
        while(i > 0){
            System.out.println(Thread.currentThread().getName() + "---" + (i--));
            //延迟程序就出错了,相同的数字出现多次(随机性和延迟导致的),输出:
/*          线程1---100
            线程2---99
            线程1---98
            线程2---98
            线程1---97
            线程2---97
            线程2---95
            线程1---96
            线程2---94
            线程1---93*/
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

解决线程安全问题原因:
    1、是否是多线程环境
    2、是否有共享数据
    3、是否有多条语句操作共享数据
1、2我们改不了,就改变3,把多条语句操作共享数据的代码宝成一个整体,让别人无法执行。
Java提供了同步机制。
同步代码块格式

synchronized(对象){需要同步的代码}
//同步可以解决安全问题的根本原因在那个对象,该对象如同锁的功能
public class RunableDemo implements Runnable {
    private int i = 100;
    //创建锁对象
    private Object obj = new Object();

    public void run() {
        while (true) {
            // 多个线程必须是同一把锁
       //
synchronized (obj) { if (i > 0) { System.out.println(Thread.currentThread().getName() + "---" + (i--)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }

改进版:

public class RunableDemo implements Runnable {
    private int i = 100;
    private Object obj = new Object();
    private int j = 0;

    public void run() {
        while (true) {
            if (j % 2 == 0) {
                synchronized (obj) {
                    if (i > 0) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()
                                + "出售" + "---" + (i--));
                    } 
                }
            } else {
                synchronized (obj) {
                    if (i > 0) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()
                                + "出售" + "---" + (i--));
                    } else {

                    }
                }
            }
        }

    }

}

同步的特点:
    前提条件:
        多个线程
        解决问题的时候多个线程必须使用同一把锁
    解决了线程安全问题
    弊端
        当线程很多时,每个线程都会去判断同步上的锁,耗费资源,降低程序效率。

如果一个方法一进去就看到了代码被同步,那么可以把同步加在方法上,同步方法的格式:

//把同步关键字加在方法上
private synchronized void sellTicket(){
    //方法体
}
同步代码块锁对象:任意对象
同步方法的锁对象:当前类(this)
静态方法及所对象问题:
    静态是随着类的加载而加载
    静态方法同步锁对象是所在类的.class文件。
List<String> list = new ArrayList<String>(); 线程不安全
List<String> list = Collection.synchronizedList(new ArrayList<String>()); 线程安全
synchronized

Lock锁

//虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,JDk5以后提供了新的锁对象Lock。
Lock
    void lock();
    void unlock();
ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo implements Runnable {
    private int i = 100;
    private Lock lock = new ReentrantLock();

    public void run() {
        while (true) {
            //使用try...finally语句,在finally语句中释放锁,最终程序都会执行到finally,释放锁就不会失败。
            try {
                //获取锁
                lock.lock();
                if(i > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO 自动生成的 catch 块
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "出售: " + (i--) );
                }
            } finally {
                //释放锁
                lock.unlock();
            }

        }
    }
}
  ReentrantLock是Lock的实现类。
同步弊端
    效率低
    如何出现了同步嵌套,就容易产生死锁。
死锁问题及其代码
    是指两个或两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象。
    同步代码块的嵌套案例。
public class DieLock implements Runnable{
    private final Object objA = new Object();
    private final Object objB = new Object();
    boolean b = false;
    public DieLock(boolean b){
        this.b = b;
    }
    //objA和objB同时等待对方释放锁,就会出现死锁情况。
    public void run() {
        if(b){
            synchronized(objA){
                System.out.println("if objA");
                synchronized(objB){
                    System.out.println("if objB");
                }
            }
        }else{
            synchronized(objB){
                System.out.println("else objB");
                synchronized(objA){
                    System.out.println("else objA");
                }
            }
        }
    }
    
}

设置获取资源:不同种类的线程针对同一资源的操作

public class Student {
    String name;
    int age;
}
//--------------------------------------
public class GetStudent implements Runnable{
    private Student s;
    public GetStudent(Student s){
        this.s = s;
    }
    public void run() {
        //获取资源并输出
        System.out.println(s.name + "---" + s.age);
    }

}

//--------------------------------------
public class SetStudent implements Runnable{
    private Student s;
    public SetStudent(){}
    public SetStudent(Student s){
        this.s = s;
    }
    //设置资源
    public void run() {
        s.name = "zed";
        s.age = 18;    
    }

}

//--------------------------------------
public class Demo {

    public static void main(String[] args) {
        //创建共有资源
        Student s = new Student();
        //设置和获取类
        GetStudent gs = new GetStudent(s);
        SetStudent ss = new SetStudent(s);
        //线程类
        Thread t1 = new Thread(gs);
        Thread t2 = new Thread(ss);
        //线程启动
        t1.start();
        t2.start();
    }

}

  上面程序t1和t2抢资源,但是如果获取线程先抢到,就无法输出资源了,因为设置线程没有设置。

  所以上面的程序是有问题的。不同种类的线程都要加锁,并且不同种类加的锁必须是同一把。改进版:

public class Student {
    String name;
    int age;
}
//--------------------------------------
public class GetStudent implements Runnable{
    private Student s;
    public GetStudent(Student s){
        this.s = s;
    }
    public void run() {
        //获取资源并输出
        while(true){
            //不同种类的线程要用同一把锁
            synchronized(s){
                System.out.println(s.name + "---" + s.age);
            }
        }
    }

}
//--------------------------------------
public class SetStudent implements Runnable{
    private Student s;
    public SetStudent(){}
    public SetStudent(Student s){
        this.s = s;
    }
    private int i = 0;
    //设置资源
    public void run() {
        while(true){
            //不同种类的线程要用同一把锁
            synchronized(s){
                if(i % 2 ==0){
                    s.name = "zed";
                    s.age = 20;    
                }else{
                    s.name = "akl";
                    s.age = 18;
                }
            }
            i++;
        }
    }

}
//--------------------------------------
public class Demo {

    public static void main(String[] args) {
        //创建共有资源
        Student s = new Student();
        //设置和获取类
        GetStudent gs = new GetStudent(s);
        SetStudent ss = new SetStudent(s);
        //线程类
        Thread t1 = new Thread(gs);
        Thread t2 = new Thread(ss);
        //线程启动
        t1.start();
        t2.start();
    }

}

线程安全解决了,但是存在如下问题:
    如果消费者先抢到CPU的执行权,就会去消费数据,但是现在的数据是默认值,没有意义,应该等着数据有意义再消费。
    如果生产者先抢到CPU的执行权,就会去产生数据,但是它产生完数据后,还继续拥有执行权,它又继续产生数据。应该等着消费者把数据消费掉,然后再生产。
正确的思路
    生产者
        先看是否有数据,有就等待,没有就生产。生产完之后通知消费者来消费。
    消费者
        先看是否有数据,有就消费,没有就等待。没有通知生产者生产。
为了处理这样的问题,Java提供了一种机制:等待和唤醒机制。
等待唤醒(Object中提供了三个方法):
    void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
    void notify() 唤醒在此对象监视器上等待的单个线程。
    void notifyAll() 唤醒在此对象监视器上等待的所有线程。
    为什么这些方法不定义在Thread中呢?
        这些方法的调用必须通过锁对象调用,而我们使用的锁对象是任意锁对象。所以必须定义在Object中。

public class Student {
    String name;
    int age;
    boolean flag;//默认情况下没有数据,如果是true,说明有数据。
}
//-------------------------------------------------------------------
public class GetStudent implements Runnable{
    private Student s;
    public GetStudent(Student s){
        this.s = s;
    }
    public void run() {
        //获取资源并输出
        while(true){
            //不同种类的线程要用同一把锁
            synchronized(s){
         //如果flag为false,则表示没有数据,则等待。
if(!s.flag ){ try { s.wait();//将来醒来是从这里开始的 } catch (InterruptedException e) { e.printStackTrace(); } }
          //flag为true,有数据输出,然后赋值flag为false,唤醒线程,大家一起来抢CPU   System.out.println(s.name
+ "---" + s.age);   //设置标记,表示没有数据。放开线程,大家一起来抢CPU。(输出了就没数据) s.flag= false; s.notify(); } } } } //------------------------------------------------------------------- public class SetStudent implements Runnable{ private Student s; public SetStudent(){} public SetStudent(Student s){ this.s = s; } private int i = 0; public void run() { while(true){ synchronized(s){
          //如果flag为true,也就是说有数据,则等待
if(s.flag){ try { s.wait();//将来醒来是从这里开始的 } catch (InterruptedException e) { e.printStackTrace(); } } if(i % 2 ==0){ s.name = "zed"; s.age = 20; }else{ s.name = "akl"; s.age = 18; } i++; //修改标记,表示有数据(创建了就有数据) s.flag = true; //唤醒线程 s.notify(); } } } } //------------------------------------------------------------------- public class Demo { public static void main(String[] args) { //创建共有资源 Student s = new Student(); //设置和获取类 GetStudent gs = new GetStudent(s); SetStudent ss = new SetStudent(s); //线程类 Thread t1 = new Thread(gs); Thread t2 = new Thread(ss); //线程启动 t1.start(); t2.start(); } }
flag为true就表示有数据,为flase表示没有数据。默认值为false,表示没有数据。先生产再消费。
set
public void run(){ while(true){ synchronized(s){ //为true表示有数据 if(s.flag){ //有数据就等待 s.wait(); } s.name = s.age = //设置了表示有数据了,唤醒线程抢CPU。 s.flag = true; s.notify(); } } } get: public void run(){ while(true){ synchronized(s){ //为false表示没有数据 if(!s.flag){ //没有数据就等待 s.wait(); } System.out.println("有数据,输出数据"); //输出完就没有数据了,唤醒线程抢CPU。 s.flag = false; s.notify(); } } }

也可以在学生类中做同步

        public synchronized void set(String name, int age){
            if(this.flag){
                try{
                    this.wait();
                }catch(InterruptedException e){
                    
                }
                this.name = name;
                this.age = age;
                
                //修改标记
                this.flag = true;
                this.notify();
            }
        }
        public synchronized void get(){
            //没有数据就等待
            if(!this.flag){
                this.wait();
            }
            System.out.println("输出");
            
            //修改标记
            this.flag = false;
            this.notify();
        }

 线程组
    Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
    默认情况下,所有线程都属于主线程组(main线程组)

 public final ThreadGroup getThreadGroup()

    我们也可以给线程设置分组

 Thread(ThreadGroup group, Runnable target, String name)

程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互,而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存周期短的线程时,更应该考虑线程池,
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池成为空闲状态,等待下一个对象来使用,
在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池。

static ExecutorService newCachedThreadPool() 
          //创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 
static ExecutorService newFixedThreadPool(int nThreads) 
          //创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。 
static ExecutorService newSingleThreadExecutor() 
          //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 
          //创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行 
//这些方法返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程,它提供了如下方法:
<T> Future<T> submit(Callable<T> task) 
          //提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。 
 Future<?> submit(Runnable task) 
          //提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 
public class ExecutorRunnable implements Runnable {

    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "----" + i);
        }
    }
}
//------------------------------------------------------------------
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo {
    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        //使用下面的方法线程就会执行,但是不会关闭。
        //直到调用shutdown()方法
        es.submit(new ExecutorRunnable());
        es.submit(new ExecutorRunnable());
        es.shutdown();
    }
}

Callable

import java.util.concurrent.Callable;

//Callable是带泛型的接口,接口泛型内的类型就是call方法返回值的类型;如果没有指定泛型类型,默认Object类。
//如果线程执行完要返回一个接口,就用Callable
public class CallableDemo implements Callable<Object> {

    @Override
    public Object call() throws Exception {
        // TODO 自动生成的方法存根
        for(int i = 0; i < 100; i++){
            System.out.println(Thread.currentThread().getName() + "----" + i);
        }
        return null;
    }

}
//------------------------------------------------------------------
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo {
    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        //使用下面的方法线程就会执行,但是不会关闭。
        //直到调用shutdown()方法
        es.submit(new CallableDemo());
        es.submit(new CallableDemo());
        es.shutdown();
        
    }
}
import java.util.concurrent.Callable;

/*
 * 线程求和案例
 */
public class MyCallable implements Callable<Integer> {

    private int number;

    public MyCallable(int number) {
        this.number = number;
    }

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int x = 1; x <= number; x++) {
            sum += x;
        }
        return sum;
    }

}
//-------------------------------------------------------
public class CallableDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(2);

        // 可以执行Runnable对象或者Callable对象代表的线程
        Future<Integer> f1 = pool.submit(new MyCallable(100));
        Future<Integer> f2 = pool.submit(new MyCallable(200));

        // V get()
        Integer i1 = f1.get();
        Integer i2 = f2.get();

        System.out.println(i1);
        System.out.println(i2);

        // 结束
        pool.shutdown();
    }
}

匿名内部类使用多线程

匿名内部类方式使用多线程
    new Thread(){
        //代码块
    }.start();
    
    new Thread(new Runnable(){
        //代码块
    }).start();

定时器
    定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能。
    Timer
        public Timer();
        public void schedule(TimerTask task, long delay);
        public void schedule(TimerTask task, long delay, long period);
    TimerTask
        public abstract void run();
        public boolean cancel();
Quartz是一个由Java编写的开源框架。

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

/*
 * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
 * 依赖Timer和TimerTask这两个类:
 * Timer:定时
 *         public Timer()
 *         public void schedule(TimerTask task,long delay)
 *         public void schedule(TimerTask task,long delay,long period)
 *         public void cancel()
 * TimerTask:任务
 */
public class TimerDemo {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer t = new Timer();
        // 3秒后执行爆炸任务
        // t.schedule(new MyTask(), 3000);
        //结束任务
        t.schedule(new MyTask(t), 3000);
    }
}

// 做一个任务
class MyTask extends TimerTask {

    private Timer t;
    
    public MyTask(){}
    
    public MyTask(Timer t){
        this.t = t;
    }
    
    @Override
    public void run() {
        System.out.println("beng,爆炸了");
        t.cancel();
    }

}
 * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
 * 依赖Timer和TimerTask这两个类:
 * Timer:定时
 *         public Timer()
 *         public void schedule(TimerTask task,long delay)
 *         public void schedule(TimerTask task,long delay,long period)
 *         public void cancel()
 * TimerTask:任务
 */
public class TimerDemo2 {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer t = new Timer();
        // 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
        t.schedule(new MyTask2(), 3000, 2000);
    }
}

// 做一个任务
class MyTask2 extends TimerTask {
    @Override
    public void run() {
        System.out.println("beng,爆炸了");
    }
}
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/*
 * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
 */

class DeleteFolder extends TimerTask {

    @Override
    public void run() {
        File srcFolder = new File("demo");
        deleteFolder(srcFolder);
    }

    // 递归删除目录
    public void deleteFolder(File srcFolder) {
        File[] fileArray = srcFolder.listFiles();
        if (fileArray != null) {
            for (File file : fileArray) {
                if (file.isDirectory()) {
                    deleteFolder(file);
                } else {
                    System.out.println(file.getName() + ":" + file.delete());
                }
            }
            System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
        }
    }
}

public class TimerTest {
    public static void main(String[] args) throws ParseException {
        Timer t = new Timer();

        String s = "2014-11-27 15:45:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse(s);

        t.schedule(new DeleteFolder(), d);
    }
}

 


        

 

 

 

 



 

 


 

 

 

 

 

 

posted on 2017-05-23 10:33  长嘴大耳怪  阅读(185)  评论(0编辑  收藏  举报