Java并发-线程基础

Posted Tim_Bergling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发-线程基础相关的知识,希望对你有一定的参考价值。

Java并发-线程基础

线程状态转移

技术图片

线程状态:

  • 新建(New)
  • 可运行(Runnable)
  • 阻塞(Blocking)
  • 无期限等待(Waiting)
  • 期限等待(Timed Waiting)
  • 死亡(Terminated)

新建

创建后未启动.

可运行

  • 可能正在运行,可能在等CPU时间片.
  • 包含Running 和 Ready.

阻塞

等待获取排它锁.

无期限等待

  • 等待其他线程唤醒.
  • 不分配时间片.
进入 退出
无参Object.wait() Object.notify()/Object.notifyAll()
无参Thread.join() 被调用程序结束
LockSupport.park()

期限等待

  • 无需其他线程显式唤醒,一定时间被系统唤醒.
  • 阻塞:被动的,等待获取排它锁;等待:主动的,通过sleep()wait()进入.
进入 退出
Thread.sleep()方法 时间结束
Object.wait(int time) 时间结束/Object.notify()/Object.notifyAll()
Thread.join(int time) 时间结束/被调用线程完成
LockSupport.parkNanos()
LockSupport.parkUntil()

死亡

线程结束任务或产生异常终止.


线程的创建

方式:

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

注:
RunnableCallable是创建一个可以在线程中运行的任务,最终线程的创建还是通过Thread来实现.

实现Runnable接口

  • 需实现run方法.
  • 通过Threadstart()方法启动线程.

实现Callable接口

  • 可以有返回值.
  • 重写call()方法.
  • 返回值通过FutureTask对象进行封装.(通过Callable对象创建FutureTask对象,再通过Thread创建线程,通过FutureTask对象获得返回值)

继承Thread类

  • 需实现run()方法.
  • 调用start()方法启动线程,JVM将线程放在就绪队列中等待调度.被调度的线程执行run()方法.

实现接口与继承Thread

  • Java非多继承,继承Thread类就无法继承其他类,但可实现多个接口.
  • 类可能只要可执行就行,继承Thread开销大.

基础线程机制

Executor

管理多个异步任务的执行,无需显式管理线程的生命周期。

分类:

  • CachedThreadPool:一个任务创建一个线程。
  • FixedThreadPool:所有任务只能使用固定大小的线程。
  • SingleThreadExecutor:大小为1的FixedThreadPool。

CachedThreadPool

ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
    es.execute(()->{
        System.out. println("This is "+Thread.currentThread().getName());
    });
}
Thread.sleep(2000);
es.shutdown();

Daemon

  • 守护线程是程序运行时在后台提供服务的线程。
  • 当所有非守护线程结束时,程序结束,同时结束其设置的所有守护线程。
  • main()属于非守护线程。
  • 使用setDaemon()将一个线程设为守护线程。(thread.setDaemon(true))

sleep()

  • 会休眠当前运行的线程指定的时间。
  • 可能抛出异常,需要捕获。

yield()

  • 声明当前线程可以切换给其他线程执行。
  • 不一定让出CPU,具体由CPU决定。

线程中断

  • 一个线程在运行期间发生异常后会提前结束。

InterruptedException

  • 对于一个处于阻塞期限等待无期限等待状态的线程,调用其interrupt()中断线程,会抛出InterruptedException异常,从而使线程提前结束。
  • interrupt不能中断I/O阻塞或synchronized锁阻塞的线程。

interrupted()

  • 使用interrupted()方法,在当前线程被其他线程interrupt()后,返回true,从而可以用于被中断后正常结束进程。

Executor的中断操作

  • shutdown()方法会等待线程都执行完毕后再关闭。
  • shutdownNow()立即关闭所有线程,相当于调用所有线程的interrupt()方法。
  • 若中断指定的线程,则创建线程时使用submit()创建一个Future对象,再调用其cancel(true)进行中断。

线程互斥同步

两种锁机制控制多线程对共享资源的互斥访问:

  • synchronized
  • ReentrantLock

synchronized

同步一个代码块

// 多线程访问同一对象时控制其互斥访问
// 若为不同对象时,则多线程互不影响
public void func() {
    synchronized (this) {
        // 共享变量访问代码
    }
}

// 同一对象,互斥访问
Thread t1 = new Thread(()->{func()});
Thread t2 = new Thread(()->{func()});

// 不同对象,互不影响
Object o1 = new Object();
Object o2 = new Object();
Thread t1 = new Thread(()->{o1.func()});
Thread t2 = new Thread(()->{o2.func()});

同步一个方法

// 同一对象,多线程互斥访问
// 不同对象,多线程互不影响
public synchronized void func () {
    // 共享变量访问代码
}

同步一个类

// 作用于整个类
// 无论是否是同一个对象,同一个类的对象都互斥访问
public void func() {
    synchronized (Test.class) {
        // 共享变量访问代码
    }
}

// 同样是作用于整个类
public synchronized static void fun() {
    // 共享变量访问代码
}

ReentrantLock

示例:

private Lock lock = new ReentrantLock();

public void func() {
    lock.lock(); // 获得锁
    try {
        // 共享变量访问代码
    } finally {
        lock.unlock(); // 释放锁,避免发生死锁。
    }
}

对比

实现

  • synchronized是JVM实现的。
  • ReentrantLock是JDK实现的。

性能

大致相当。

等待可中断

  • 持有锁的线程长期不释放锁,等待线程可以放弃等待。
  • ReentrantLock可中断,synchronized不可中断。

公平锁

公平锁:多个线程等待同一个锁时,按照申请的先后顺序获得锁。

  • synchronized是非公平的。
  • ReentrantLock可以是公平的,也可是非公平的。

绑定条件

一个ReentrantLock可以绑定多个Condition对象。


线程间的协作

join()

  • 当一个线程调用另外一个线程的join()方法,则当前线程挂起,直到另外线程完成后,该线程继续运行。

wait(),notify(),notifyAll()

  • 调用wait(),使得当前线程被挂起,直到其他线程调用同一个对象实例notify()notifyAll()来唤醒挂起的线程。
  • wait()notify()notifyAll()都必须在synchronized修饰的方法内使用,否则抛出异常。
  • wait()挂起线程后,当前线程获得的锁会释放。
  • sleep()是Thread类的静态方法,并且不会释放锁。

await(),signal(),signalAll()

  • 创建Lock对象,利用Lock对象生成Condition
  • 调用Condition上的await()方法使得线程等待,其他线程调用signal()signalAll()方法唤醒等待的线程。

参考:


以上是关于Java并发-线程基础的主要内容,如果未能解决你的问题,请参考以下文章

java并发编程基础——线程的创建

[Think In Java]基础拾遗4 - 并发

Java并发编程之美之并发编程线程基础

Java多线程与并发库高级应用-工具类介绍

Java多线程与并发库高级应用-工具类介绍

Java并发专题之二Java线程基础