并发编程笔记——第一章 并发编程基础

一、线程的创建与运行

  1. 实现Runable接口的run方法,作为Thread的构造参数

  2. 继承Thread类,重写run方法(好处:this等价于Thread.curentThread();坏处:java只能单继承)

  3. 使用FutureTask方式(好处,可以获取返回结果)

样例3:

import javax.swing.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Main extends JFrame {

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

    static class CallerTask implements Callable<String> {
        @Override
        public String call() throws Exception {
            Thread.sleep(3000L);
            return "AAA";
        }
    }
}

tip:start方法只是让线程处于就绪状态,并非立即启动

二、线程交互基础方法

  1. obj.wait():线程挂起,直到 1.其他线程调用obj.notify()或obj.notifyAll(); 2.其他线程调用thread1.interrupt();
  2. obj.notify:唤醒一个obj挂起的线程,但该线程必须和其他线程竞争obj锁,抢到了才能继续执行
  3. obj.notifyAll:唤醒所有
  4. thread1.join:等待线程执行完毕,阻塞
  5. Thread.sleep:线程会暂时让出指定时间的执行权,但监视器资源(如:锁)仍持有,时间过后线程处于就绪状态,获取CPU资源后就可以继续运行
  6. Thread.yield:暗示线程调度器当前线程请求让出自己的CPU使用(即告诉线程调度器我剩下的时间片不要了,你执行下一轮调度吧),但是可能被忽略
  7. thread1.interrupt:给thread1设置中断标志,当thread1调用wait,join,sleep而被阻塞挂起时,抛出异常,中断线程
  8. Thread.isInterrupted():当前线程是否中断,不清除标志
  9. Thread.interrupted():当前线程是否中断,清除标志

tip:

  1. 调用wait或是notify方法之前都需要获取该对象的监视器锁1:synchronized(obj){}; 2:synchronized void f(){wait();}; obj.f();
  2. 线程可能存在虚假唤醒,即没有线程调用obj.notify的情况下被唤醒
  3. wait方法只会释放当前对象的监视器锁,其他监视器锁仍处于持状态

三、上下文切换的概念

  • CUP资源的分配采用了时间片轮转的策略,也就是给每个线程分配一个时间片,线程在时间片内占用CPU执行任务。当前线程使用完时间片后,就会处于就绪状态并让出CPU给其他线程占用,这就是上下文切换。切换时需要保存当前线程的执行现场,当再次执行时根据保存的信息恢复执行现场。

切换时机:1、时间片用完处于就绪状态; 2、线程被其他线程中断

四、死锁条件

  • 互斥条件:锁资源有排他性
  • 请求并持有条件:1、有锁资源》》2、请求其他锁》》3、其他锁被占有》》4、阻塞同时不释放锁资源
  • 不可剥夺条件:获取到的锁资源在自己用完之前不能被其他线程占有
  • 环路等待条件:A等B,B等C,C等A

避免死锁的方法:破坏四个条件之一,当前只能破坏请求并持有环路等待

  • 例如:资源申请有序性原则(只有获取了第n-1个资源才能申请获取第n个资源)

五、守护线程和用户线程

  • 当最后一个非守护线程结束时,JVM会正常退出
  • 设置守护线程:thread.setDaemon(true);

六、ThreadLocal与InheritableThreadLocal

  1. ThreadLocal:1、每个线程操作ThreadLocal共享变量时都会复制一个副本到本地线程,所以操作的都是本地线程变量;2、变量不支持父子线程的继承
  2. InheritableThreadLocal:支持父子线程的继承,是在new Thread()的时候复制父线程inheritableThreadLocals的一个副本到子线程,本质上还是互相独立的

例ThreadLocal:

public class Main extends JFrame {
    static ThreadLocal<String> localValue = new ThreadLocal<>();

    public static void main(String[] args) throws FileNotFoundException, InterruptedException {

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                localValue.set("1");
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 为空
                System.out.println(localValue.get());
            }
        });
        thread1.start();
        thread2.start();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值