多线程实现方式

Thread

继承Thread-->重写run()--->创建并且初始化对象--->对象名点start

class Demo{
    public static void main(String[] args){
        MutiThread aThread = new MutiThread();
        aThread.start();
    }
}

class MutiThread extends Thread{
    @override
    public void run(){
        System.out.println("这是一个线程");
    }
}

注意:

  • 每个Thread对象就是一个线程
  • 只有start以后线程才会开始运行,直接对象名点run()只是调用方法,并不是启动线程
  • 启动多个对象需要创造多个Thread对象

Runnable

实现Runnable接口-->重写run()-->创建并且初始化对象--->创建Thread对象-->Thread对象名点start

class Demo{
    public static void main(String[] args){
        MutiRunnable aThread = new MutiRunnable();
        Thread thread = new Thread(aThread);
        thread.start();
    }
}

class MutiRunnable implements Runnable{
    @override
    public void run(){

    }
}

注意:

  • Runnable方式的多线程中,run()方法中的东西相当于任务,当创建了实现Runnable接口的对象时即为创建了任务,当再创建Thread对象时,就相当于将任务放在了线程中

callable

实现callable接口-->重写run()-->创建并实例化实现接口的类-->创建Thread对象-->Thread对象名点start

class Demo{
    public static void main(String[] args){
        MutiCallable aThread = new MutiCallable();
        Thread thread = new Thread(MutiCallable);
        thread.start;
    }
}

class MutiCallable implements Callable{
    @override
    public Object call(){
        run 0;
    }
}

控制api

休眠api --- sleep

sleep(long millis)使当前运行的程序停下来,数据类型为long,单位为毫秒

合并api---join

join()有三个重载的方法分别是

voidjoin()  等待这个线程死亡。
voidjoin(long millis)  等待这个线程死亡最多 millis毫秒。
voidjoin(long millis,  int nanos)  等待最多 millis毫秒加上 nanos纳秒这个线程死亡。

守护api ---daemon

voidsetDaemon(boolean on)  将此线程标记为 daemon线程或用户线程。


注意:

  • 需要在线程启动前进行调用
  • 当正在运行的线程都为守护线程时,JVM会退出虚拟机

礼让api---yeid

暂停当前正在进行的线程对象

注意:由于Java虚拟机采取的是抢夺类型的,所以当暂停当前的线程后,当前线程也会假如争抢的队列,有可能会再次强盗

中断api --- stop / interrupter

interrupter

不能真正的中断线程

stop

可以中断线程,但是存在安全性问题

数据安全问题

产生原因

  • 多线程读取数据

  • 非原子操作(原子操作:一个操作要么执行完,要么不执行)

解决办法

synchronized

synchronized(Object){ 
    //需要上锁的的代码块
}

注意括号:

  • 括号中可以是任意类对象,但是要和类中的成员变量统一

  • Java中的所有对象,都有一个标志位,来表示加锁和解锁的状态

    加锁之后,当线程退出同步代码块时,JVM会自动清理标志位,使其变成未家所状态

lock

Lock lock = new ReentrantLock();//创建对象
lock.lock;//加锁
{
    //上锁代码块,大括号可以不要
}
lock.unlock;//解锁

两种方法的区别:

  • sychorinize不用创建对象,JVM隐式上锁解锁,lock需要创建对象,有完成的上锁和解锁操作d
  • N久之前lock的效率要高于synchronized,但现在已经差不多了synchronized的

死锁

产生原因

两个线程的一部分必要资源都在对方手里的来进行下一步骤,从而导致程序阻塞

线程通信

  • wait当前线程自我阻塞
  • notify()唤醒一个阻塞的线程
  • notifyAll()唤醒所有阻塞线程

线程池

ExecutorServer newCacheThreadPool()
  • 会根据需要创建新的线程,也可以自动删除,60s处于空闲状态的线程
  • 线程数量可以变,立马执行提交的异步任务(异步任务:在子线程中执行的任务)
ExecutorServer newFixedThreadPool()
  • 线程数量固定(fixed:固定的)
  • 维护一个无界队列(队列:先进先出),暂存已提交的来不及执行的任务
  • 按照任务提交的顺序将任务执行完毕
ExecutorServer newSingleThreadExecutor()
  • 单个线程
  • 维护一个无界队列(队列:先进先出),暂存已提交的来不及执行的任务
  • 按照任务提交的顺序将任务执行完毕