Java多线程相关的一些知识

Java多线程相关的一些知识

1 创建多线程的方法

创建多线程的方法有3种:

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口

1.1 继承Thread类实现多线程

继承Thread类,实现主线程main和子线程同时运行:

public class ANewThread extends Thread{
    public ANewThread(String name){
        super(name);
    }
    @Override
    public void run() {
        while(true){
            System.out.println(this.getName() + " 运行中");
        }
    }
    public static void main(String[] args){
        ANewThread aNewThread = new ANewThread("子线程");
        aNewThread.start();
        while (true) {
            System.out.println("main线程 运行中");
        }
    }
}

1.2 实现Runnable接口实现多线程

实现Runnable接口,实现主线程main和子线程同时运行:

public class ANewThread implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("子线程运行中");
        }
    }

    public static void main(String[] args) {
        new Thread(new ANewThread()).start();
        while (true) {
            System.out.println("主线程运行中");
        }
    }
}

1.3 实现Callable接口实现多线程

实现Callable接口,实现主线程main和子线程同时运行:

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

public class ANewThread implements Callable {
    @Override
    public Object call() throws Exception {
        Thread.sleep(2000);
        return "hello";
    }

    public static void main(String[] args) {
        FutureTask<String> futureTask = new FutureTask<String>(new ANewThread());
        new Thread(futureTask).start();
        try {
            String result = futureTask.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

实现Callable接口和其它两种方法的区别是:

  • Callable可以返回类型
  • Callable能够抛出checked exception
  • 未列出

2 线程终止的方法

线程终止的方法:

  • 正常终止:main/run方法结束
  • 非正常终止:抛出异常
  • 受控终止:
    • 使用thread.stop(弃用)方法
    • 使用thread.interrupt()方法
    • 使用boolean标志位终止线程(加上volatile)

使用boolean停止标志位终止线程(加上volatile)的方法终止线程,为什么要加上volatile?

  • 假设具有终止标志的线程为线程A,当其它线程希望线程A终止时,修改停止标志位为true(初始为false),该修改希望立即被线程A观测到。
  • 当加上volatile后,线程A每次查看标志位时,都不能从线程本地内存中读取,必须到主内存中读取,于是可以立即响应终止请求。

3 volatile关键字

volatile关键字的功能:

  • 保证变量可见性
  • 禁止指令重排序

volatile如何实现保证变量可见性?

在Java内存模型JMM中,将内存分为两大块:主内存(线程公有),工作内存(线程私有)。

对被volatile修饰的变量:

  • 读操作之前加入内存屏障,可理解为清除该变量在线程工作内存中的值,从而使得线程必须去主内存中取该值
  • 写操作之后加入内存屏障,可理解为将要清除该变量在线程工作内存中的值,从而使得线程必须将值存入到主内存中

4 synchronized关键字

4.1 synchronized关键字和锁

synchronized关键字的功能:

  • 保证被修饰的代码块同一时间内只有一个线程可以执行

synchronized关键字的功能是如何实现的?

使用“锁”机制实现。每个Java对象都有一个锁(堆内存中对象头部的一部分),所有线程访问一个对象,都必须获得这个对象的锁。
synchronized将一个对象的锁赋予给一个代码块,让线程访问该代码块的时候必须先获得该对象的锁,从而保证这段代码块在同一时间内只有一个线程可以执行。

synchronized获取不同的锁的类型:

  • 对象锁 - (使用对象锁监视一个代码块)
  • 类锁 - (本质上也是对象锁,使用本类class对象的锁监视本类)
  • 方法锁 - (调用该方法的实例变量对象的锁)

4.2 Java中的锁

Java中的锁有两种:

  • synchronized锁
  • Lock锁(ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock)

synchronized锁和Lock锁都是是可重入锁,互斥锁。
ReentrantLock默认为非公平锁,但可设置为公平锁。

可重入锁:

  • 获得锁的线程内部可以分享锁
  • 例子:
    • 类结构
      • 类的同步方法A
        • 调用同步方法B
      • 类的同步方法B
        • 执行一些操作
    • 当调用同步方法A时,如果锁的类型不是可重入锁,则会导致同步方法B不能获得锁,造成死锁。

非公平锁:
不按照锁的申请顺序来分配锁,如果锁刚空闲时恰好有一个线程来申请锁,就把锁给那个线程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值