zoukankan      html  css  js  c++  java
  • 多线程

    多线程的概述
        进程:
              正在运行的程序,是系统进行资源分配和调用的独立单位
              每一个进程都有它自己的内存空间和系统资源
        线程:
              进程中的单个顺序控制流,是一条执行路径
              一个进程如果只有一条执行路径,则成为单线程程序
              一个进程如果有多条执行路径,则成为多线程程序。
              一个进程内可以执行多个任务,则每个任务是一个线程。
        多进程有什么意义?
              单进程计算机只能做一件事,现在的计算机同一时间段内可以执行多个任务,提高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);
        }
    }


            



     

    
    
    

     

  • 相关阅读:
    SpringBoot + SwaggerUI
    eclipse环境下:lombok安装及使用
    mysql列名名称包含特殊字符的处理
    java.lang.UnsupportedClassVersionError: com/mysql/cj/jdbc/Driver : Unsupported major.minor version 5
    PL/SQL连接远程服务器数据库,出现ORA-12154: TNS: 无法解析指定的连接标识符。
    tnsping无法ping通的问题,TNS-12535 TNS操作超时 (服务器环境:window server 2008R2 数据库环境:oracle 11 g)
    使用数据泵expdp、impdp备份和还原oracle数据库
    sql sever 2012重装数据库时,出现cannot find one or more components, Please reinstall the application.解决方法
    SQL Sever 2012版本数据库的完全安装流程
    SQL Sever 2012版本数据库的完全卸载
  • 原文地址:https://www.cnblogs.com/changzuidaerguai/p/6892918.html
Copyright © 2011-2022 走看看