Java多线程详解

Java多线程

1. 实现线程的三种方式


1.1 继承Thread类

继承Thread类首先得重写run方法

class Thread1 extends Thread {
	@Override
    public void run(){
        super.run();
    }
    
    public void static main(string[] args){
        Thread1 th = new Thread1();
        //调用run方法不会同时执行。
        th.run();
        //start方法开启线程,与主线程同时运行,交替执行
        th.start();
    }
}

1.2 实现runnable接口

class PrimeRun implements Runnable {
    long minPrime;
    PrimeRun(long minPrime) {
        this.minPrime = minPrime;
    }

    public void run() {
        // compute primes larger than minPrime
        . . .
    }
}
//The following code would then create a thread and start it running:
PrimeRun p = new PrimeRun(143);
     new Thread(p).start();

推荐使用runnable接口的实现方式,由于Java单继承类的局限性,方便一个对象被多个线程使用

new Thread(p,"name1").start;
new Thread(p,"name2").start;

1.3 实现Callable接口

步骤:

  • 实现callable接口(需要返回值类型)

    • class PrimeRun implements Callable<返回值类型>
      
  • 重写call方法

    带返回值

  • 创建目标对象

  • 使用线程池

    • ExecutorService s = Executors.newFixdeThreadPool(3);
      
    • Future<> f = s.submit(对象);
      
    • f.get()
      
    • s.shutdownNow();
      

2.静态代理

真实对象和代理对象都要实现同一个接口。

代理对象要代理真实角色。

好处:代理对象可以做很多真实对象做不了的事情。

线程中 Thread就相当于代理对象,他与自己定义的线程类都实现了 runnable接口

3.Lambda表达式

new Thread(()->System.out.println("多线程")).start();

为什么要使用Lambda表达式?

  1. 避免匿名内部类过多
  2. 简洁代码
  3. 去掉无意义的代码,只留下核心逻辑

函数式接口 Functional Interface

  • 定义

    任何接口只要只包含唯一一个抽象方法,那么他就是一个函数式接口

    public interface Runnable{
    	public abstract void run();
    }
    
  • 对于函数式接口,我们可以通过Lambda表达式来创建该接口的对象

写lambda表达式的前提就是先有函数式接口

4.线程状态

线程的五大状态:

  • 创建状态
  • 就绪状态
  • 阻塞状态
  • 运行状态
  • 死亡状态

4.1线程停止

不推荐使用JDK提供的stop() 暴力停止线程,已经弃用、destroy()方法

推荐

  1. 线程自己停下来,利用次数,不建议死循环

  2. 使用一个标志位进行终止变量,当flag=false,则线程终止运行

    //设置一个公开的方法停止线程
    class PrimeRun implements Runnable {
        long minPrime;
        boolean flag = true;
        PrimeRun(long minPrime) {
            this.minPrime = minPrime;
        }
    
        public void run() {
            // compute primes larger than minPrime
            while(flag){
            	...
            }
        }
        
        //停止线程
        public void stop(){
        	this.flag = false
        }
    }
    
  3. 使用interrupt()

    public class InterruptThread1 extends Thread{
    
        public static void main(String[] args) {
            try {
                InterruptThread1 t = new InterruptThread1();
                t.start();
                Thread.sleep(200);
                t.interrupt();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            super.run();
            for(int i = 0; i <= 200000; i++) {
                System.out.println("i=" + i);
            }
        }
        
    }
    

4.2线程休眠(sleep)

sleep()方法来让线程休眠

每个对象都有锁,sleep不会释放锁

主要用于

  • 模拟网络延时
  • 倒计时
  • 显示时间

4.3线程礼让(yield)

礼让不一定会成功,将当前线程转为就绪状态,与其他进程再次同时竞争CPU,不一定礼让成功

yield()

4.4线程强制执行(join)

join合并线程,待此线程执行完成后,再执行其他线程

死亡的线程不能再启动

5.线程优先级

main方法默认优先级为5(范围是1-10)

优先级高的会先执行,(也不百分百会先执行)

6.守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕如 main方法
  • 虚拟机不用等待守护线程执行完毕如后台记录操作日志、监控内存、垃圾回收等

设置守护线程

threadname.setDaemon(true);//默认为false,即为用户线程

7.线程同步

每个对象都有一把锁

线程安全:

加了synchronized关键字的方法都必须获得调用该方法的对象的锁才能执行,否则会线程阻塞

缺陷:

会影响效率

对于普通同步方法,锁是当前实例对象。 如果有多个实例 那么锁对象必然不同无法实现同步。
对于静态同步方法,锁是当前类的Class对象。有多个实例 但是锁对象是相同的 可以完成同步。
对于同步方法块,锁是Synchonized括号里配置的对象。对象最好是只有一个的 如当前类的 class 是只有一个的 锁对象相同 也能实现同步

8.显式加锁lock

与synchronized代码块不同

ReentrantLock(可重入锁)可以实现显式加锁

ReentrantLock lock = new ReentrantLock();
lock.lock();
try{
	//to do....
}finally{
	lock.unlock();
}

使用lock锁,jvm将花费较少时间调度线程,性能更好,具有更好的扩展性

使用顺序

  • lock>同步代码块>同步方法

9.线程池

ExecutorService和Executors

ExecutorService service = Executors.newFixedThreadPool(10);
//执行callable使用submit,带返回值
//执行runnable使用execute,不带返回值
service.execute();
service.submit();
//关闭连接
service.shutdown();

Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值