美文网首页
多线程编程基础

多线程编程基础

作者: engineer_tang | 来源:发表于2020-07-14 18:45 被阅读0次

实现多线程的3种方式

(1)继承Thread

package com.threadtest;

public class ThreadNormal extends Thread {

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

    @Override
    public void run() {
        System.out.println("线程\"" + Thread.currentThread().getName() + "\"开始执行!");
        for(int i = 0; i < 100; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
        }
    }

    public static void main(String[] args) {
        System.out.println("线程\"" + Thread.currentThread().getName() + "\"开始执行!");
        ThreadNormal threadNormal = new ThreadNormal("线程1");
        threadNormal.start();
        for(int i = 0; i < 100; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
            
        }
    }
}

(2) 实现Runnable接口

package com.threadtest;

public class ThreadByRunnable implements Runnable {

    @Override
    public void run() {
        for(int i = 0; i < 100; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
        }
    }

    public static void main(String[] args) {
        System.out.println("线程\"" + Thread.currentThread().getName() + "\"开始执行!");
        ThreadByRunnable threadByRunnable = new ThreadByRunnable();
        Thread thread = new Thread(threadByRunnable, "实现Runable接口线程1");
        thread.start();
        for(int i = 0; i < 100; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));

        }
    }
}

(3) 实现Callnable接口

package com.threadtest;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadByCallnable {

    public static void main(String[] args) {
        FutureTask<Integer> futureTask = new FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for(; i < 100; i++) {
                System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {

                }
            }
            return 487;
        });
        Thread thread = new Thread(futureTask, "Callable接口线程1");
        thread.start();
        for(int i = 0; i < 100; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
            if(i == 19) {
                try {
                    System.out.println(futureTask.get());
                }catch (InterruptedException e) {

                } catch (ExecutionException e) {

                }
            }
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {

            }
        }


    }
}

注: FutureTask调用get方法时,会导致主线程阻塞,直到FutureTask线程执行完毕。
(4) 三种实现方式对比
采用实现Runable、Callable接口的方式创建多线程的优缺点

  1. 线程类通过实现Runable接口或Callable接口,还可以继承其他类。
  2. 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
    劣势:编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。

采用继承Thread类的方式创建多线程的优缺点:
劣势:因为线程类已经继承了Thread类,不能再继承其他类了。
优势:编写简单,如果需要访问当前线程,可以直接使用this即可。
(5) 线程的生命周期
线程要经过的阶段包括新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、和死亡(Dead)。
(6) 控制线程

  1. join线程
    某个线程执行过程中,调用了其他线程的join方法时,调用线程将被阻塞,知道被调的其他线程执行完为止,才能继续执行调用线程。
package com.threadtest;

public class ThreadByRunnable implements Runnable {

   @Override
   public void run() {
       for(int i = 0; i < 100; i++) {
           System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
       }
   }

   public static void main(String[] args) {
       System.out.println("线程\"" + Thread.currentThread().getName() + "\"开始执行!");
       ThreadByRunnable threadByRunnable = new ThreadByRunnable();
       Thread thread = new Thread(threadByRunnable, "实现Runable接口线程1");
       thread.start();
       for(int i = 0; i < 100; i++) {
           System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
           if(i == 19) {
               try{
                   thread.join();
               }catch (InterruptedException e) {

               }
           }
       }
   }
}

  1. 后台线程
    特点:为其他线程提供服务,后台运行;所有前台线程死亡,后台线程自动死亡。
    实现:调用Thread对象的setDaemon(true)
package com.threadtest;

public class ThreadByRunnable implements Runnable {

    @Override
    public void run() {
        for(int i = 0; i < 100; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
        }
    }

    public static void main(String[] args) {
        System.out.println("线程\"" + Thread.currentThread().getName() + "\"开始执行!");
        ThreadByRunnable threadByRunnable = new ThreadByRunnable();
        Thread thread = new Thread(threadByRunnable, "后台线程1");
        thread.setDaemon(true);
        thread.start();
        for(int i = 0; i < 10; i++) {
            System.out.println(String.format("线程\"%s\"打印的数为:%s ", Thread.currentThread().getName(), i));
        }
    }
}

3)线程睡眠sleep
让当前正在执行的线程暂停millis毫秒,并进入阻塞状态,该方法受到系统计时器和线程调度器的精度与准确度的影响。

  1. 线程让步yield
    让当前线程暂停,不会阻塞,让线程调度器重新调度一下,只有和线程优先级相同或更高的线程才会获得执行的机会。
  2. 改变线程优先级
    使用方法:setPriority(int newPriority)
    特点:
    优先级范围在1-10之间,Thread有三个静态常量,分别是MAX_PRIORITY(10)、MIN_PRIORITY(1)、NORM_PRIORITY(5).
    优先级别越高获得执行机会就越多,优先级别越低获得执行机会就越少。
    每个线程的默认优先级都与创建它的父线程优先级相同,默认情况下,main线程具有普通优先级,由main线程创建的子线程也具有普通优先级。

相关文章

网友评论

      本文标题:多线程编程基础

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