天天看点

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

以下学习内容来自此处:https://www.bilibili.com/video/BV1V4411p7EF

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

线程创建

Java中线程创建的方式有三种:

  • 继承

    Thread

  • 实现

    Runnable

    接口
  • 实现

    Callable

    接口

继承Thread类

  • 自定义类继承

    Thread

  • 重写

    run()

    方法
  • 创建线程对象,调用

    start()

    方法
public class ThreadByExtendsThreadClass extends Thread{

    @Override
    public void run() {
        for(int i = 0; i <= 200; ++i){
            System.out.println("thread...." + i);
        }
    }

    public static void main(String[] args) {
        
        ThreadByExtendsThreadClass threadByExtendsThreadClass = new ThreadByExtendsThreadClass();
        threadByExtendsThreadClass.start();
        

        for(int i = 0; i <= 200; ++i){
            System.out.println("main....." + i);
        }
    }
}
           

调用

start()

启动线程不一定立即执行,需要根据CPU分配。

实现Runnable接口

  • 实现

    Runnable

    接口:

    implements Runnable

  • 实现

    run()

    方法
  • 创建

    Thread

    线程类对象,并调用

    start()

    方法来启动
public class ThreadByImplementRunnable implements Runnable{
    
    @Override
    public void run() {
        for(int i = 0; i <= 200; ++i){
            System.out.println("thread..." + i);
        }    
    }


    public static void main(String[] args) {
        
        new Thread(new ThreadByImplementRunnable()).start();


        for(int i = 0; i <= 233; ++i){
            System.out.println("main..." + i);
        }
    }

}
           
继承Thread类 实现Runnable接口
子类继承Thread类后具备多线程的能力 实现接口Runnable具有多线程能力
启动线程的方式:

子类对象.start()

启动方式:

Thread(目标对象).start()

不建议使用:避免OOP单继承局限性

推荐使用:避免单继承局限性,灵活方便,

且同一个对象可以别多个线程调用

使用

Runnable

接口实现的方式是通过 静态代理 。

实现Callable接口

  • 实现

    Callable<>

    接口,指定call返回值类型
  • 重写

    call

    方法,需抛出异常
  • 创建目标对象
  • 创建执行服务:

    ExecutorService ser = Executors.newFixedThreadPool(线程池大小)

  • 提交执行:

    Feature<Boolean> res = ser.submit(目标对象)

  • 获取结果:

    boolean res = res.get()

  • 关闭服务:

    ser.shutdownNow()

好处:可以定义返回值以及抛出异常

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadsImplementCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for(int i = 0; i < 10; ++i){
            System.out.println(Thread.currentThread().getName() + "   " + i);
        }
        return Thread.currentThread().getName() + " done!";
    }


    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ThreadsImplementCallable t[] = new ThreadsImplementCallable[3];
        for(int i = 0; i < 3; ++i){
            t[i] = new ThreadsImplementCallable();
        }

        ExecutorService executorService = Executors.newFixedThreadPool(3);
        
        List<Future<String>> res = new ArrayList<>();
        for(int i = 0; i < 3; ++i){
            res.add(executorService.submit(t[i]));
        }
        for(int i = 0; i < 3; ++i){
            System.out.println(res.get(i).get());
        }

        executorService.shutdownNow();
    }
}
           

仅有一个方法的接口称为函数式接口

匿名内部类没有类的名称,但需要借助接口或者父类

线程的状态

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池
[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池
[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池
[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

stop

对于让线程停止的方式,建议使用 设置标志循环检测 来实现终止。

sleep

指定当前线程 阻塞 的毫秒数, 存在异常

IntertuptedException

, 时间达到后进入 就绪 状态。每个对象都有一个锁,sleep不会释放

yield

线程礼让,及将线程转为 就绪状态,此时交由CPU调度,可能会执行其他线程也可能不会。

join

合并线程,待该线程执行完毕后,在执行其他线程,其他线程阻塞。(插队)

线程的优先级

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

守护线程(daemon)

线程分为 用户线程 和 守护线程 ; 其中虚拟机必须确保用户线程执行完毕,而不用等待守护线程执行完毕,如后台的日志、监控内存、垃圾回收(gc)

thread.setDaemon(true)

即设置该线程为保护线程。(默认为false)

线程同步

并发:同一对象被多个线程同时操作。

锁机制:

synchronized

,排他锁,存在以下问题:

  • 一个线程持有后其他线程挂起
  • 多线程竞争中,频繁加锁和释放会导致较多的上下文切换和调度延时,性能问题
  • 优先级高的等待优先级低的释放锁,会导致优先级倒置,性能下降。

synchronized

默认锁的是this对象。

死锁

死锁的必要条件:

  • 互斥条件
  • 请求与保持条件
  • 不剥夺条件
  • 循环等待条件

(避免synchronized块中请求多个资源)

Lock

不加锁时:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest {
    public static void main(String[] args) {
        Ticket ticket1 = new Ticket();

        new Thread(ticket1, "1").start();
        new Thread(ticket1, "2").start();
        new Thread(ticket1, "3").start();
    }
}

class Ticket implements Runnable {

    int ticketnum = 10;

    @Override
    public void run() {

        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            if (ticketnum >= 0) {
                System.out.println(Thread.currentThread().getName() + " get " + ticketnum-- + "...");
            } else {
                break;
            }
        }

    }
}
           

使用ReentrantLock加锁后:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest {
    public static void main(String[] args) {
        Ticket ticket1 = new Ticket();

        new Thread(ticket1, "1").start();
        new Thread(ticket1, "2").start();
        new Thread(ticket1, "3").start();
    }
}

class Ticket implements Runnable {

    int ticketnum = 10;
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            try {
                lock.lock();
                if (ticketnum >= 0) {
                    System.out.println(Thread.currentThread().getName() + " get " + ticketnum-- + "...");
                } else {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

    }
}
           

对比:

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

线程通信

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

线程池

[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池
[笔记]-Java多线程简要学习线程创建线程的状态线程的优先级守护线程(daemon)线程同步死锁Lock线程通信线程池

实现方式即

Callable

那里的;前者使用的是 submit来执行,也可以使用

execute()

方法实现。

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadsPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());
        executorService.execute(new MyThread());

        executorService.shutdown();
    }    
}


class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
           

更加深入的多线程学习以及JUC可以查看这里https://www.bilibili.com/video/BV1B7411L7tE