编程语言
首页 > 编程语言> > 前人栽树后人乘凉:《深入浅出 Java 多线程》

前人栽树后人乘凉:《深入浅出 Java 多线程》

作者:互联网

1. 线程概述

1.1 线程和进程

1.2 多线程的优势

2. 线程创建与启动

2.1 继承Thread

public class FirstThread extends Thread {
    private int i;

    @Override
    public void run() {
        for(i = 0; i < 50; i ++){
            System.out.println(this.getName() + "" + i);
        }
    }

    public static void main(String[] args){
        FirstThread ft = new FirstThread();
        for(int i =0; i < 100;i ++){
            System.out.println(Thread.currentThread().getName() + "" + i);
            if(i == 20) {
                ft.run();
            }
        }
    }
}

2.2 实现Runnable接口

public class FirstThread implements java.lang.Runnable {
    private int i;

    public void run() {
        for(i = 0; i < 50; i ++){
            System.out.println(Thread.currentThread().getName()+ "" + i);
        }
    }

    public static void main(String[] args){
        FirstThread ft = new FirstThread();
        for(int i =0; i < 100;i ++){
            System.out.println(Thread.currentThread().getName() + "" + i);
            if(i == 20) {
                ft.run();
            }
        }
    }
}

2.3 使用Callable和Future

方法名作用
boolean cancel(boolean mayInterruptIfRunning)试图取消该Future里关联的Callable任务
V get()返回Callable任务里call方法的返回值,该方法会造成线程阻塞,等子线程执行完才能获得
V get(long timeout, TimeUnit unit)返回Callable任务里call方法的返回值。该方法让程序最多阻塞timeoutunit指定的时间,如果经过指定时间Callable任务还没有返回值则抛出TimeoutException异常
boolean isCancelled()Callable中的任务是否取消
boolean isDone()Callable中的任务是否完成

public class CallableDemo {
    public static void main(String[] args){
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for( ; i < 100; i++){
                System.out.println(i);
            }
            return i;
        });
        new Thread(task).start();
        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

2.4 创建线程的三种方式对比

RunnableCallable优劣势:

Thread优劣势:

3. 线程生命周期

3.1 新建和就绪状态

3.2 运行和阻塞状态

线程状态转换图

3.3 死亡状态

4. 控制线程

4.1 join线程

4.2 后台线程(Daemon Thread)

public class DaemonThread extends Thread {
    @Override
    public void run() {
        for(int i = 0; i< 1000; i++){
            System.out.println("DaemonActivity" + i);
        }
    }

    public static void main(String[] args){
        DaemonThread thread = new DaemonThread();
        thread.setDaemon(true);
        thread.start();
        for(int i = 0; i < 10; i ++ ){
            System.out.println("MainActivity" + i);
        }
    }
}

运行结果

4.3 线程睡眠sleep

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

4.4 改变线程优先级

5. 线程同步

5.1 同步方法

public class DaemonThread extends Thread {

    static int balance = 100;
    int drawAmount;
    String name;

    public DaemonThread(int drawAmount, String name){
        this.drawAmount = drawAmount;
        this.name = name;
    }

    @Override
    public void run() {
        this.draw(drawAmount);
    }

    public synchronized void draw(int amount){
        if(balance  >= amount){
            System.out.println(this.name + "取出了" + amount);
            try{
                Thread.sleep(1);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
            balance -= amount;
            System.out.println("\t余额为" + balance);

        } else{
            System.out.println(this.name + "取现失败");
        }
    }
    public static void main(String[] args){
        new DaemonThread(50, "A").start();
        new DaemonThread(100, "B").start();
    }
}

5.2 释放同步监视器的锁定

下列情况下,线程会释放对同步监视器的锁定

下列情况下不会释放:

5.3 同步锁

方法名作用
lock加锁
unlock解锁

5.4 死锁

A等B,B等A

5.5 线程通信

5.5.1 传统的线程通信

方法名作用
wait导致当前线程等待,直到其他线程调用该同步监视器的notify()notifyAll()方法
notify唤醒在此同步监视器等待的单个线程
notifyAll唤醒在此同步监视器等待的所有线程

5.5.2 使用Condition

方法名作用
await导致当前线程等待,直到其他线程调用该同步监视器的signal()signalAll()方法
signal唤醒在此Lock对象的单个线程
signalAll唤醒在此Lock对象的所有线程

5.5.3 使用阻塞队列

方法名作用
put(E e)尝试把E元素放入BlockingQueue
take()尝试从BlockingQueue的头部取出元素

public class BlockingQueueThread extends Thread {

    private BlockingQueue<String> bq;

    public BlockingQueueThread(BlockingQueue<String> bq){
        this.bq = bq;
    }

    @Override
    public void run() {
        String[] strColl = new String[]{
                "Java",
                "Kotlin",
                "JavaScript"
        };



        for(int i = 0; i < 1000; i ++){
            try {
                System.out.println(getName() + "开始动工" + i);
                bq.put(strColl[i % 3]);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println(getName() + "工作结束");
    }

    public static void main(String[] args){
        BlockingQueue<String> bq = new ArrayBlockingQueue<>(5);
        new BlockingQueueThread(bq).start();
    }
}

结果展示

可以看到,当Thread-0运行到第6次时就已经被阻塞,不能往里添加内容

6. 线程组和未处理的异常

方法名作用
int activeCount返回线程组中活动线程的数目
interrupt中断此线程组中所有活动线程的数目
isDaemon线程组是否是后台线程组
setDaemon设置后台线程
setMaxPriority设置线程组的最高优先级

7. 线程池

7.1 ThreadPool

public class ThreadPoolTest {

    public static void main(String[] args){
        ExecutorService pool = Executors.newFixedThreadPool(2);

        java.lang.Runnable target = () -> {
           for (int i = 0; i < 100 ; i ++){
               System.out.println(Thread.currentThread().getName() + "的i为" +i);
           }
        };

        pool.submit(target);
        pool.submit(target);
        pool.shutdown();
    }
}

结果展示

7.2 ForkJoinPool

public class PrintTask extends RecursiveAction {

    public static int THREADSH_HOLD = 50;

    private int start;

    private int end;

    public PrintTask(int start, int end){
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        if(end - start < THREADSH_HOLD){
            for(int i = start; i < end; i ++){
                System.out.println(Thread.currentThread().getName() + "的i为" + i);
            }
        } else {
            PrintTask left = new PrintTask(start, (start + end) / 2);
            PrintTask right = new PrintTask((start + end) / 2 , end);
            left.fork();
            right.fork();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        PrintTask printTask = new PrintTask(0 , 300);
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(printTask);
        pool.awaitTermination(2, TimeUnit.SECONDS);
        pool.shutdown();

    }
}

结果展示 

 这是小编为大家准备一些资料

 

需要的扫码加微信免费领取哦!

标签:Thread,int,void,前人栽树,线程,后人乘凉,多线程,方法,public
来源: https://blog.csdn.net/m0_60720471/article/details/120862759