Java多线程

作者: dpengwang | 来源:发表于2018-05-17 20:53 被阅读0次

    概念

    程序:指令集,静态概念

    进程: 操作系统 ,调度程序 ,动态概念,占用特定的地址空间,由cpu data code 组成,缺点占内存,CPU负担重。pid

    线程:又称为轻量级进程,是进程中的一个单一的连续控 流程。线程之间相互独立。一个进程可拥有多个并行的线程。线程间的通行时在同一地址空间上进行的 ,所以不需要额外的通行机制,可以共享变量,也会造成并发问题。是进程内多条执行路径。(真正的多线程只存在于多cpu机器,单CPU属于模拟多线程,时间片实现(挂起))

    进程是资源分配的基本单位,线程是资源调度的基本单位

    多线程实现

    main方法也是个线程,被称主线程

    通过继承Thread类

    (1)创建多线程重写run方法(方法体),一切从run开始(alt+shift+s 重写父类的方法)

    (2)使用多线程:创建子类对象,调用对象 的start方法(start只是加到了线程组里,cpu调用的时候才是真正执行。不是调用run方法,内部会自己调用。调用run方法就是普通的方法调用,只有一条路径)

    package com.pku.java.secondstage;
    import java.io.IOException;
    import java.sql.Time;
    
    class ThreadA extends Thread{
        public void run() {
            // TODO Auto-generated method stub
            try{
            for(int i=0;i<=100;i++){
                System.out.println("thread A run"+i+"steps");
                sleep(100);
            }}
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class ThreadB extends Thread{
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try{
            for(int i=0;i<=100;i++){
                System.out.println("thread B run"+i+"steps");
                sleep(100);
            }}
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }   
    }
    
    public class ThreadTest {
        public static void main(String args[]){
            ThreadA A =  new ThreadA();
            ThreadB B=  new ThreadB();
            A.start();
            B.start();
            for (int i=0;i<=100;i++){
                System.out.println("this is the "+i+"step of main thread");
            }
        }   
    }
    

    对于继承了Thread的实例对象,只需调用其start方法,之后如何调度由cpu处理。

    通过实现Runnable接口

    (1)实现runnable接口并重写run方法

    (2)启用多线程使用静态代理(代理者为Thread)

    • 创建真实角色
    • 创建代理角色,添加真实角色的引用

    (3) 调用代理的Start方法

    好处 避免单继承的局限性,便于共享资源

    class hello implements Runnable{
        public void run(){
          for(int i=0;i<=1000;i++) {
              System.out.println("输出中文");     
          }
        }
    }
    public class DclientTest {
        public static void main(String args[]){
            hello aHello = new hello();
            Thread proxya =  new Thread(aHello);
            proxya.start();
            for(int i=0;i<1000;i++){
                System.out.println("print english");
            }
        }
    
    }
    

    eg:

    模拟多个线程抢票

    public class Web12306 implements  Runnable {
        private int num=50;
        public void run() {
            while(true){
                if(num<=0)
                    break;
            System.out.printf(Thread.currentThread().getName()+"抢到了",num--);
            System.out.println();
            }
            
        }
        
        public static void main(String args[]){
            Web12306 test  =  new Web12306();
            Thread aThread =  new Thread(test);
            Thread bThread =   new Thread(test);
            Thread cThread = new Thread(test);
            aThread.start();
            bThread.start();
            cThread.start();    
        }
    }
    

    核心方法只有一个,代理可以有多个。代理同时执行即多线程

    小结:两种实现多线程的方法

    1. 继承Thread+run():通过创建子类对象并调用对象的start()方法

    2. 实现Runnable接口和run()方法:通过使用静态代理

      1.创建真实角色

      2.创建代理角色 Thread+引用

      3.代理角色.Start()

    第二种方法的优点,避免单继承的局限性,便于共享资源

    前两种方法只能通过try来声明异常不能抛出,也不能返回值,这时要用到第三种创建线程的方法

    通过Callable接口

    优点:可以获取返回值

    Callable和Future接口

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

    具体实现:

    1)创建Callable实现类+重写Call

    2)借助执行调度服务ExecutorService,获取Future对象

    ExecutorService ser  =  Executors.newFixedThreadPool(2);//开启线程数
    
    Future <Integer> result = ser.submit(实现类对象); //<返回值类型>
    

    3)获取值

    result.get()
    

    4)停止服务

    ser.shutdownNow()
    

    Callable和Runnable的不同:

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

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

    (3)Callable的任务执行后可以返回值,运行Callable任务可以拿到一个Future队 形,而Runnable的任务是不能返回值的,Future对象表示异步计算的结果,通过这个对象可以了解任务的执行情况,或者可以取消任务的执行,还可以获取任务执行的结构

    import java.util.FormatFlagsConversionMismatchException;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Executor;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class ThridRunTest {
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            ExecutorService ser  =  Executors.newFixedThreadPool(2);
            Race tortoise = new Race("tortoise",200);
            Race rabit =  new Race("rabit",50);
            Future <Integer> result1 = ser.submit(tortoise);
            Future <Integer> result2 = ser.submit(rabit);
            
            Thread.sleep(2000);// 让线程运行两秒钟停下
            tortoise.setFlag(false);
            rabit.setFlag(false);
                    
            int nums1 = result1.get();
            System.out.println("the tortoise has run-->"+nums1);
            int nums2 = result2.get();
            System.out.println("the rabit has run-->"+nums2);
            ser.shutdown(); 
        }
    
    }
    class Race implements Callable<Integer>{
        private String name;
        private long time;
        public long getTime() {
            return time;
        }
        private boolean flag =true;
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
        private int step =0;
        public  Race(String name) {
            super();
            this.name =name;
            // TODO Auto-generated constructor stub
        }
        public  Race(String name,long time) {
            super();
            this.name =name;
            this.time  =time;
            // TODO Auto-generated constructor stub
        }
        @Override
        public Integer call() throws Exception {
            // TODO Auto-generated method stub
            while(flag){
                Thread.sleep(time);
                step++;
            }
            return step;
        }
        public String  getName(){
            return this.name;   
        }   
    }
    

    output:

    the tortoise has run-->10
    the rabit has run-->40
    

    线程的状态

    线程状态:

    新生状态:

    用new关键字建立一个线程对象后, 该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间, 通过调用start进入就绪状态

    就绪状态:
    处于就绪状态线程具备了运行条件, 但还没分配到CPU, 处于线程就绪队列, 等待系统为其分配CPU。当系统选定一个等待执行的线程后, 它就会从就绪状态进入执行状态, 该动作称之为“cpu调度” 。

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

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

    死亡状态:
    死亡状态是线程生命周期中的最后一个阶段。 线程死亡的原因有三个。 一个是正常运行的线程完成了它的全部工作; 另一个是线程被强制性地终止, 如通过执行stop方法来终止一个线程[不推荐使用】 , 三是线程抛出未捕获的异常

    停止线程

    1.自然终止:线程体执行完毕

    2.外部干涉:

    1. 线程类中定义线程体使用的标志
    2. 线程体中使用该标志
    3. 提供对外的方法改变该标识
    public class ThreadStopTest {
        public static void main(String[] args) throws InterruptedException {
            Study aStudy =  new Study();
            new Thread(aStudy).start();
            
            Thread.sleep(2000);
            aStudy.setFlag(false);
            
        }
        
    }
    class Study implements Runnable{
    //  public Study() {
    //      // TODO Auto-generated constructor stub
    //  }
        private boolean flag =true;
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while(flag){
                System.out.println("the thrad is running");
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }   
    }
    
    线程阻塞

    两种方法:

    (1)join:合并线程

    public class ZuseTest implements Runnable{
        
        public static void main(String args[]) throws InterruptedException{
            ZuseTest aTest = new ZuseTest();
            Thread aThread = new Thread(aTest);
            aThread.start();
            int i=0;
            while(true){
                System.out.println(i);
                i++;
                if (i==50) aThread.join();
                Thread.sleep(300);
            }
        }   
        public void run() {
            for (int i=0;i<=100;i++){
                System.out.println("A");
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }   
        }
    }
    

    开始时主线程和子线程并行执行,等到i=50的时候,执行athread.join(),主线程(main)被阻塞,直到aThread线程执行完毕再执行主线程。

    (2)yield:暂停线程,暂停当前正在执行的执行对象,暂停自己(是个静态方法)

    写在哪个线程里面就暂停谁

    public class YieldTest implements Runnable{
    
        @Override
        public void run() {
            for (int i=0;i<=1000;i++){
                System.out.println("this is Thread"+i);
            }
            
        }
        public static void main(String[] args) {
            Thread aThread  = new Thread(new YieldTest());
            aThread.start();
            int i=1;
            while(true){
                if(i >500) break;
                i++;
                System.out.println("main ==>"+i);
                if(i % 20 ==0){
                    Thread.yield();         
                }
            }
        } 
    }
    

    被暂停的线程可能会被cpu再次调度

    (3)sleep(静态方法)

    休眠,暂停当前进程,休眠的时候不会释放锁。

    作用:

    • 计时
    • 模拟网络延迟

    相关文章

      网友评论

        本文标题:Java多线程

        本文链接:https://www.haomeiwen.com/subject/htvidftx.html