GYM1-并发基础和Thread类详解

GYM是葛一鸣老师的简写。GYM系列文章都是观看葛老师课程的个人笔记。

线程的优势

1.发挥多处理器的强大能力
2.代码责任单一,方便调试
3.异步事件的简化处理,防止客户端阻塞
4.响应更灵敏的用户界面

多线程危害

1.线程安全性可能是非常复杂的,线程执行顺序是不可预测的,竞争条件,脏读。
2.活跃性问题:某件正确的事情最终会发生,死锁。
3.性能问题:context Switch 切换、影响性能。

java线程状态

1.New:状态 已经分配内存,无cpu时间
2.Runable: 资源已经全部分配,可能在已经分配cpu时间
3.blocked:进入临界区,被挂起
4.waiting:等他其他线程唤醒,或者定时唤醒
5.terminated:终止状态
x\

java线程的操作

  • Thread的start()在新的线程中调用run()方法,单纯吊用run()方法不会开启一个新的线程。
  • 两种方法新建:
    (1)传递一个实现Runable的类;
    (2)重载Thread的run()方法;
  • 每个线程都拥有自己的名字;

    终止线程

  • thread.stop() 不建议使用,过于暴力,直接终止,可能导致数据的不一致,。
  • thread.interruput() 中断线程,只是给相应的线程打招呼,并不会真的终端线程
  • thread.isInterruput() 判断线程是否被中断,采取相应的措施
  • thread.sleep() InterruptedException
    在sleep过程中其他线程发送中断请求 ,可以在catch中做出中断处理。
    中断异常的时候清空中断标志位,catch中需要重新设置中断标志,while中使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    static class InterruptedThread implements Runnable {
    @Override
    public void run() {
    while (true) {
    if (Thread.currentThread().isInterrupted()) {
    System.out.println("i am breaking");
    break;
    }
    try {
    System.out.println("i want to sleep");
    Thread.sleep(5000);
    } catch (InterruptedException e) {
    System.out.println("someone interrupt me");
    //恢复中断标志位
    Thread.currentThread().interrupt();
    }
    }
    }
    }

    public static void main(String[] args) throws InterruptedException{
    Thread thread = new Thread(new InterruptedThread(), "t1");
    thread.start();
    Thread.sleep(7000);
    thread.interrupt();
    }

输出结果:

1
2
3
4
i want to sleep
i want to sleep
someone interrupt me
i am breaking

六、线程挂起和继续执行

不建议使用,resume()发生在suspend之前时,线程无法释放锁处于runnable转台

  • tread.suspend() 占用锁不释放
  • thread.resume() 重启线程

七、等待和谦让(debugger、测试可能使用)

  • thread.yield() 释放当前线程的cpu时间,但是还是继续竞争,
  • thread.join()等待线程结束
    调用线程等待join函数的所属线程结束

    join实现代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public final synchronized void join(long millis)
    throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;
    if (millis < 0) {
    throw new IllegalArgumentException("timeout value is negative");
    }
    if (millis == 0) {
    while (isAlive()) {
    wait(0);
    }
    } else {
    while (isAlive()) {
    long delay = millis - now;
    if (delay <= 0) {
    break;
    }
    wait(delay);
    now = System.currentTimeMillis() - base;
    }
    }
    }

守护线程

在后台默默完成一些系统性的服务,如GC、JIT理解为守护线程
setDeamon();在start之前设置
如果没有业务线程守护线程也会死掉。

线程优先级

setPriority(Thread.MAX_PRORITY)
高优先级程序不一定就能一直抢占cpu时间,只是几率高一些

线程同步

  • synchronized
    (1)指定加锁对象
    (2)修饰实例方法:相当于当前对象加锁
    (3)直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁
  • object.wait()、object.notify()、notifyAll()
    没有获得监视器之前不能使用wait(),会释放当前线程的监视器,通知其他线程执行;
    notify之后不会立即启动wait方法,拿到锁之后可以继续执行wait之后的事情。唤醒所有等待监视器的线程中的其中一个线程。notifyAll唤醒所有的线程,去争用监视器。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        public static Boolean flag = true;

    public static class Task implements Runnable {
    @Override
    public void run() {
    try {
    //必须获取监视器才能用wait 会排数InterruptedException
    synchronized (flag) {
    System.out.println("im ready to wait");
    flag.wait();
    System.out.println("someone notify me");
    }
    } catch (InterruptedException e) {

    }
    }
    }

    public static void main(String[] args) throws Exception {
    new Thread(new Task()).start();
    Thread.sleep(5000);
    synchronized (flag) {
    TestWaitNotify.flag.notifyAll();
    }
    }

    输出结果
    /**
    *im ready to wait
    *someone notify me
    */