zoukankan      html  css  js  c++  java
  • 线程类、线程池

    线程类 Thread

    两个构造方法 空参和有参

    空参Thread():分配一个新的thread对象,不可指定名字

    有参 Thread(String name):创建一个新线程,可起名

    常用方法:

    start():开启线程

    run():执行 描述任务

    sleep(long millis):设置毫秒值 让正在执行的线程休眠

    创建线程步骤

    1.先继承thread类  2.重写run 3.创建子类对象(线程对象)4.调用start方法,开启线程让线程执行,让jvm调用run方法

    线程对象调run和调start区别

    线程调用run开启线程。调Start 开启线程,让jvm调用run在开启线程中执行

    why?继承Thread类原理

    Thread类是个默认类,用来描述,我们定义的这个线程做Thread的子类,是为了利用其Thread本有的功能,子继承父,并拥有它的功能

    创建线程目的:

    目的有单独路径,让多部分代码同时执行

    原理图

    看似两个方法同时在运行,其实是CPU快速的切换所以两边都在执行

    package com.oracle.demo01;
    新建子类
    public class MyThread extends Thread{
    //    重写run方法
        public void run() {
            for(int i=0;i<20;i++){
                System.out.println("myThread-"+i);
            }
            super.run();
        }
    }
    package com.oracle.demo01;
    测试
    public class Demo01 {
        public static void main(String[] args) {        
    //        创建新线程(创建子类对象)
            MyThread thread=new MyThread();
    //        开启线程 调start()
            thread.start();
            for(int i=0;i<20;i++){
                System.out.println("main-"+i);
            }
        }
    }

    创建线程方式(继承Thread类)

    获取线程名称 

    currentThread()用谁调用就会返回调用当前方法线程的对象

    getName()以前获取方法名是用报错的方法获取名称,现在可以直接用getName来代表

    在新线程里获得名称,直接用getName就可以,因为里面没有静态

    在main里想获得主线程,先获得主线程的对象,在获得主线程名称

    package com.oracle.demo01;
    //定义一个类继承Thread
    public class MyThread extends Thread{
    //    重写run方法
        public void run() {
    //        getName()获取当前线程名称
            System.out.println("线程名称为"+getName());
            for(int i=0;i<20;i++){
                System.out.println("myThread-"+i);
            }
            super.run();
        }
    }
    package com.oracle.demo01;
    //用.currentThread()获取名称
    public class Demo01 { public static void main(String[] args) { // 获取执行当前代码线程的线程对象 Thread th=Thread.currentThread(); // 获取该线程的名称 System.out.println(th.getName()); // 创建新线程(创建子类对象) MyThread thread=new MyThread(); // 开启线程 调start() thread.start(); for(int i=0;i<20;i++){ System.out.println("main-"+i); } } }

    创建线程方式-实现Runnable接口(推荐)

    接口中的方法 run():

    Thread类构造方法

    步骤:

    1.定义类实现Runnable接口

    2. 覆盖接口的run方法

    3.创建Thread类对象

    4 .强Runnable接口子类对象作为参数传递给Thread类的构造函数

    5.调用Thread类的start()开启线程

    package com.oracle.demo01;
    //定义一个类 实现Runnable
    //让它实现Runnable 让MyRunnable作为新线程任务
    public class MyRunnable implements Runnable{
        
        public void run() {
            for(int i=0;i<20;i++){
                System.out.println("Thread-0"+i);
            }
        }
    } 
    package com.oracle.demo01;
    //测试Runnable类接口
    public class Demo02 {
        public static void main(String[] args) {
    //        创建线程任务对象 :MyRunnable:描述任务
            MyRunnable mr=new MyRunnable();
    //        创建Thread类对象:开启线程
            Thread th=new Thread(mr);
    //        开启线程
            th.start();
            for(int i=0;i<20;i++){
                System.out.println("main-"+i);
            }
        }
    }

    实现Runnable原理为什么用Runnable

    RunnableThread的接口,“推荐用接口的方式”生成线程,因为接口可以实现多继承 避免单一继承局限性,如果用Thread类,只能继承和创建Thread,如果用Runnable可以实现后可再继承,比Thread多了个备用功能 覆盖Runnable接口的run方法,将线程任务定义到run方法中。将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象思想将任务封装成对象

     线程匿名内部类

     匿名内部类最后得到的是子类或实现对象

    package com.oracle.demo01;
    //两个匿名内部类方式
    public class Neibulei {
        public static void main(String[] args) {
            /*new 父类或接口名(){
                需要重写方法
            }*/
    //        1.创建线程方式 继承Thread类
            new Thread(){            
    //            重写run(): 写出run然后alt+/
                public void run() { 
                    System.out.println(getName()+"这是新线程任务");
                }
    //            匿名内部类方式:创建和开启线程一步到位
            }.start();
    //        2.实现Runnable接口
            Runnable run=new Runnable(){
                public void run() {
    //                获取当前执行线程对象
                    String name=Thread.currentThread().getName();
                    System.out.println(name+"这是匿名内部类第二个方式");
                }    
    //        最后得到的是线程任务对象
            };
            new Thread(run).start();
        }
    }

    pm

    线程池

    概念:一个容纳多个线程的容器,可以反复使用,省去创先线程的操作,不用反复创建,消耗资源

    线程状态

    线程池原理

    Runnable接口:无返回值,不可抛异常、throws 都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法

    package com.oracle.demo02;
    
    //实现Runnable
    public class MyRun implements Runnable{
    //    重写里面的run方法
        @Override
        public void run() {
    //        获取执行当前线程对象的名字
            String name=Thread.currentThread().getName();
            for(int i=0;i<20;i++){
                System.out.println(name+i);//描述线程任务,让线程做什么任务
    //            让这个线程每次执行完都休息一下设置休息毫秒值
    //            这里为什么用try catch :这里的run()是Runnable接口的方法,如果父类方法没抛异常,子继承父,实现重写方法,不能抛,只能try catch
                try {
    //                打印一次线程 休眠5秒 
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }        
        }    
    }
    
    
    package com.oracle.demo02;
    
    public class Demo01 {
        public static void main(String[] args) {
    //        创建线程任务对象
            MyRun mr=new MyRun();
    //        创建线程对象
            Thread th=new Thread(mr);
    //        开启线程
            th.start();
        }
    }

    package
    com.oracle.demo02; //用接口Runnable的方式实现线程任务 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo02 { public static void main(String[] args) { // 用线程池的方式完成线程工厂任务 // 1.从线程池工厂中获取装有两条线程池的线程池对象 ExecutorService es=Executors.newFixedThreadPool(2); // 2.创建线程任务对象 MyRun mr=new MyRun(); // 让线程池自主选一条线程执行线程任务 es.submit(mr); es.submit(mr); es.submit(mr);//这里有三个线程任务 但只能完成两条任务 第二个会等第一个的有空了就执行 // 关闭线程池(一般不关) es.shutdown();//关就调用shutdown 关闭后就无法在取线程 } }

     Callable接口:用来指定线程任务,call方法 有返回值, 可以throws,有泛型 与返回值类型相同,

    import java.util.concurrent.Callable;
    
    public class MyCallable implements Callable<String>{
        public String call() throws Exception {
            return "abc";
        }
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class Demo01 {
        public static void main(String[] args) throws InterruptedException, ExecutionException {
    //      1.从线程池工厂中获取线程池对象
            ExecutorService es=Executors.newFixedThreadPool(2);
    //      2.创建线程任务对象
            MyCallable mc=new MyCallable();
    //      3.让线程池自主选择一条线程执行线程任务
            Future<String>    f=es.submit(mc);
    //      4.获取线程任务的返回值
            System.out.println(f.get());
        }
    }

     Future接口:记录线程任务执行完毕后产生的结果  线程池创建与使用

     get() 获取Future对象中封装的数据结果

    import java.util.concurrent.Callable;
    
    public class MyCall implements Callable<Integer>{
        private int num;
        private int num1;
        public MyCall(){}
        public MyCall(int num,int num1){
            this.num=num;
            this.num1=num1;
        }
        public Integer call() throws Exception {
    //       计算求和
            int sum=0;
            for(int i=num;i<=num1;i++){
                sum+=i;
            }
            return sum;
        }
    }
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class Demo01 {
        //用线程池计算50到100的和------44.....200的和
        public static void main(String[] args) throws InterruptedException, ExecutionException {
    //      1.从线程池工厂获取线程池对象
            ExecutorService es=Executors.newFixedThreadPool(2);
    //      2.创建线程任务对象
            MyCall mc1=new MyCall(50,100);
            MyCall mc2=new MyCall(44,200);
    //      3.让线程池自主选择线程执行任务
            Future<Integer> f1=es.submit(mc1);
            Future<Integer>    f2=es.submit(mc2);
    //      4.获取线程任务返回值
            int sum1=f1.get();
            int sum2=f2.get();
            System.out.println(sum1);
            System.out.println(sum2);
        }
    }

    多线程

    线程安全:多线程和单线程每次运行结果相同,其他变量值也和预期一样,就是线程安全

    线程同步:Synchronized

    ①、同步代码块:

      synchronized (锁对象) {
    
            可能会产生线程安全问题的代码
    
    }
    public class Tickets implements Runnable {
        // 创建售票类
        // 定义100张票
        private int tickect = 100;
        // 定义同步锁--必须定义在外面 表示所有的线程都使用同一个锁!
        Object obj = new Object();
        public void run() {
            while (true) {
                /*同步代码块将可能会产生线程安全问题的代码包起来---
                各个线程经过时都需要带着锁obj而进行下一步,如果没有的话需要在此等待。
                同时这个线程结束的时候将锁归还,这样下一个线程就可以拿着这个锁进行下一步操作!
                obj可以写成本类对象的this,因为其唯一性,不需要上面的定义!*/
                synchronized (obj) {
                    if (tickect > 0) {
                        try {
                            //假设休眠50--这里是制造线程不安全的情况!只是举例的一种!!
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        // 先赋值后--
                        System.out.println(Thread.currentThread().getName() + ":出售第" + tickect-- + "张票");
                    }
                }
            }
        }
    }
    public class Demo01 {
        public static void main(String[] args) {
            //1.创建线程任务
            Tickets tickets=new Tickets();
            //创建三个线程完成同一个任务
            Thread t1=new Thread(tickets);
            Thread t2=new Thread(tickets);
            Thread t3=new Thread(tickets);
            //开启线程
            t1.start();
            t2.start();
            t3.start();
        }
    }

    同步代码方法

    public synchronized void method(){
    
           可能会产生线程安全问题的代码
    
      }
    public class Tickets2 implements Runnable {
        // 创建售票类
        // 定义100张票
        private int tickect = 100;
        // 定义同步锁--必须定义在外面 表示所有的线程都使用同一个锁!
        Object obj = new Object();
        public void run() {
            while (true) {
                method();
            }
        }
        public synchronized void method() {
            if (tickect > 0) {
                try {
                    // 假设休眠50--这里是制造线程不安全的情况!只是举例的一种!!
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 先赋值后--
                System.out.println(Thread.currentThread().getName() + ":出售第" + tickect-- + "张票");
            }
        }
    }

    静态同步方法: 在方法声明static synchronized

    public static synchronized void method(){
    
        可能会产生线程安全问题的代码
    
      }

    静态同步方法中的锁对象类名.class(字节码(.class)文件的对象<字节码文件一进内存就自动生成字节码文件对象>唯一性)

    lock接口

    lock 获取锁   unlock 释放锁

    package com.oracle.demo01;
    //接口锁
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    public class Tickets3 implements Runnable {
        // 定义100张票
        private int tickect = 100;
        //创建锁接口对象---用于解决可能出现因为异常而导致锁不被还回来
        Lock lock=new ReentrantLock();
        public void run() {
            while (true) {
                //获取锁
                lock.lock();
                if (tickect > 0) {
                    try {
                        // 假设休眠50--这里是制造线程不安全的情况!只是举例的一种!!
                        Thread.sleep(50);
                        System.out.println(Thread.currentThread().getName() + ":出售第" + tickect-- + "张票");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }finally{
                        //释放锁
                        lock.unlock();        
                    }
                    // 先赋值后--                
                }
            }
        }
    }
  • 相关阅读:
    bzoj 1031: [JSOI2007]字符加密Cipher
    python re模块实现计算器
    python sys模块和序列化模块
    python time时间模块
    python 发红包的小程序
    python ranndom模块及生成验证码
    python os模块练习题
    python os模块常用命令
    快速排序,归并排序
    选择排序和插入排序
  • 原文地址:https://www.cnblogs.com/zs0322/p/11066960.html
Copyright © 2011-2022 走看看