线程

作者: 咔狼 | 来源:发表于2018-09-24 20:45 被阅读0次

Thread

  • 可以实现多部分程序的同时执行
  • 多线程可以合理使用CPU的资源,然而如果线程过多将会导致性能降低
  • 每条线程都有自己的名称,主方法的线程名为main,新建线程的默认名从Thread-0开始依次递增
  • 默认创建的线程为用户线程

线程的使用方法

方法1
  • 定义一个类并继承Thread类
  • 重写run方法
  • 调用start方法开启线程
class Demo extends Thread{
    @Override
    public void run(){
        // 任务
    }
}

Demo d1 = new Demo();
// 启动线程
d2.start();
方法2(推荐)
  • 定义一个类并实现Runnable接口
  • 重写run方法
  • 创建Thread类对象
  • 将Runnable接口的子类对象作为参数传递给Thread类的构造方法
  • 调用Thread类的start方法开启线程
class Demo2 implements Runnable{
    @Override
    public void run() {
        // 任务
    }
}

Demo2 d = new Demo2();
// 创建Thread类对象,将Runnable接口的子类对象作为参数传递给thread类的构造方法
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
// 启动线程
t1.start();
t2.start();

线程的运行安全

线程的运行流程
同步代码块
  • 使用一个对象作为锁
    一个栗子
Object obj = new Object();
public void run(){
    while(true){
        synchronized(obj){
            //需要同步的代码
        }
    }
}
同步方法
  • 同步方法的锁对象是this
  • 静态同步方法的锁对象是类名.class
    一个栗子
public synchronized void sale(){
    //需要同步的代码
}
线程常用方法

sleep()强迫一个线程睡眠N毫秒
join()等待线程终止
currentThread()得到当前线程(拿到当前方法所在的线程对象)
isDaemon()一个线程是否为守护线程
setDaemon()设置一个线程为守护线程
setName()为线程设置一个名称
wait()强迫一个线程等待
notify()通知一个线程继续运行
setPriority()设置一个线程的优先级

单例模式线程安全

多线程操作单例模式(延迟加载方式)时所发生的问题:

  • 并发访问会有安全隐患,所以加入同步机制解决安全问题,但是同步的出现降低了效率
  • 通过双重判断的方式,解决效率问题,减少判断锁的次数

栗子1 -- 无线程安全问题

class Single {
    private Single() {}
    private static final Single s = new Single();
    public static Single getInstance() {
        return s;
    }
}

栗子2 -- 延迟加载方式线程安全问题解决方案

class Single2 {
    private Single2() {}
    private static final Single s2 = null;
    public static Single getInstance() {
        if (s2 == null) {
            synchronized (Single2.class) {
                if (s2 == null) {
                    s2 = new Single2();
                }
            }
        }
        return s2;
    }
}
接口Lock与监视器对象(Condition)
  • 接口Lock将锁定义为对象,所以锁的监视器方法(wait,notify,notifyAll)也替换成新锁的监视器方法
  • 将原有的锁方法封装到了Condition对象中,想要获取监视器方法,要先获取Condition对象
  • Condition对象的出现,替代了Object中的监视器方法

监视器方法:
await()线程进入等待
signal()随机唤醒一个等待线程
signalAll()唤醒所有等待线程

Lock与Condition代码实例 -- 生产者与消费者问题

class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;
    // 定义一个锁对象
    private Lock lock = new ReentrantLock();
    // 获取锁上的Condition对象
    // 为了解决本方唤醒对方问题, 可以一个锁创建两个监视器对象
    private Condition producer = lock.newCondition();// 生产
    private Condition consumer = lock.newCondition();// 消费
    public void set(String name) {
        // 获取锁
        lock.lock();
        try {
            // 随机抽取线程进入锁, while判断标记为false则执行生产代码, 如果为true则等待
            while (flag) {
                try {
                    producer.await();
                } catch (InterruptedException e) {
                    e.printStackTrance();
                }
                this.name = name + count;
                count ++;
                System.out.println(Thread.currentThread().getName() + "..生产者.." + this.name);// 生产商品
                flag = true;
                // 执行消费线程的唤醒, 随机唤醒一个消费线程释放锁
                consumer.signal();
            }
        } finally {
            lock.unlock;
        }
    }
    public void out() {
        lock.lock();
        try {
            // 随机抽取线程进入锁, while判断标记为false则执行生产代码, 如果为true则等待
            while (!flag) {
                try {
                    consumer.await();
                } catch (InterruptedException e) {
                    e.printStackTrance();
                }
                System.out.println(Thread.currentThread().getName() + "..消费者.." + this.name);// 消费商品
                // 标记修改为false
                flag = false;
                // 随机唤醒一个生产线程释放锁
                producer.signal();
            }
        } finally {
            lock.unlock;
        }
    }
}
sleep()与wait()的区别

相同点:

  • 可以让线程除于冻结状态

不同点:

  1. sleep必须指定时间,wait可以指定也可以不指定时间
  2. sleep时间一到,线程处于临时阻塞状态或运行状态,wait如果没有指定的时间,必须要通过notify或者notifyAll唤醒
  3. sleep不一定非要定义在同步中,wait必须要定义在同步中
  4. 都定义在同步中时,线程执行到sleep不会释放锁,而线程执行到wait会释放锁

线程的细节

停止线程
  • stop方法已过时,不推荐使用
  • 当线程任务执行结束时(run方法结束),线程结束
  • 使用interrupt方法强制中断线程
守护线程
  • 守护线程为后台线程,后台线程会随着前台线程的结束而结束
  • 在启动线程前使用setDaemon(true)将线程设置为守护线程
线程的优先级
类型 字段 注释
static int MAX_PRIORITY 线程可以具有的最高优先级----优先级范围(10)
static int MIN_PRIORITY 线程可以具有的最低优先级----优先级范围(5)
static int NORM_PRIORITY 分配给线程的默认优先级----优先级范围(0)
等待线程终止

join()等待该线程终止

  • t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程
线程临时暂停

Thread.yield()临时停止当前正在运行的线程,让另外的线程执行

匿名线程

使用匿名内部类创建匿名线程以及实现Runnable接口
一个栗子

// 匿名内部类
new Thread() {
    @Override
    public void run() {
        // 任务
    }
}.start();
// 实现Runable接口创建线程
Runnable r = new Runnable() {
    @Override
    public void run() {
        // 任务
    }
};
new Thread(r).start();

相关文章

  • Android

    线程间通信 主线程和工作线程主线程和工作线程 工作线程与工作线程工作线程与工作线程 为什么主线程Looper.lo...

  • 三、操作系统之线程

    前言 什么是线程 引入线程的原因 线程的概念 线程和进程的关系 线程结构 线程有点 多线程模型 用户线程和内核线程...

  • Thread

    队列 线程锁 多线程,线程池 队列 多线程爬虫示例 多线程 自定义线程 线程池

  • 总结多线程与设计模式+synchronized+性能+高吞吐+死

    Java线程 Java语言的线程 何谓线程 线程启动 线程的暂时停止 线程的共享互斥 线程的协调 线程的状态转移 ...

  • 多线程编程

    摘要 线程概念,线程与进程的区别与联系学会线程控制,线程创建,线程终止,线程等待了解线程分离与线程安全学会线程同步...

  • java线程池

    线程VS线程池 普通线程使用 创建线程池 执行任务 执行完毕,释放线程对象 线程池 创建线程池 拿线程池线程去执行...

  • java并发之守护线程

    java中有两种线程,用户线程和守护线程用户线程:主线程停止时,用户线程不会停止守护线程:主线程停止时,守护线程也...

  • Java线程池的使用

    线程类型: 固定线程 cached线程 定时线程 固定线程池使用 cache线程池使用 定时调度线程池使用

  • 线程基础知识

    线程学习 线程的基础知识 线程是什么? 线程和进程的关系 线程的6个状态 线程优先级 主线程、多线程、后台线程的概...

  • 多线程介绍

    一、进程与线程 进程介绍 线程介绍 线程的串行 二、多线程 多线程介绍 多线程原理 多线程的优缺点 多线程优点: ...

网友评论

      本文标题:线程

      本文链接:https://www.haomeiwen.com/subject/miyhoftx.html