2.Java并行基础

对应《实战java高并发程序设计》第二章内容。

1.线程与进程

1.概念

进程简单的理解就是一个运行的程序,线程是程序执行的最小单位,是轻量级的进程。

2.线程状态

新建,运行,阻塞,等待(有时限,无时限),终止
阻塞:比如遇到synchronized同步块,直到获得锁之后才继续运行。
有时限等待:sleep(1000),睡一秒钟
无时限等待:wait(),join()…等到了期望的事件之后,继续运行。

2.线程的基本操作

1.新建线程

2.终止线程

为什么不建议用Thread.stop()?
直接终止线程,并且会立即释放这个线程所拥有的锁,而这些锁用来维持对象的一致性的,可能会造成悲剧。
如何退出呢?

private volatile boolean stop = false;
    @Override
    public void run() {
        while (true){
            if (stop){
                break;
            }
            System.out.println("一直运行。。。。。");
        }
    }

3.线程中断

线程中断不是让线程停止,而是告诉线程,有人希望你退出,怎么处理,由线程自身决定,如果线程什么都不管的话,中断不会用什么作用(当线程sleep或wait时,中断线程会唤醒它们,如下图:)。
在这里插入图片描述

//中断线程
public void interrupt() {
}
//判断是否被中断
public boolean isInterrupted() {
}
//判断当前线程是否被中断
public static boolean interrupted() {
   return currentThread().isInterrupted(true);
}

通过判断中断来退出循环体,效果更为强劲,wait,sleep中都可以接收到中断。

public void run() {
        while (true){
           if (Thread.interrupted()){
               break;
            }
           System.out.println("一直运行。。。。。");
        }
}
4.等待(wati)和通知(notify)

这两个方法是在Object上的。当线程调用了对象的wait后,会等待,直到另外一个线程调用了该对象的notify(notifyAll),才会唤醒。
在调用这两方法前,要先获得该Object的监视器。线程调用wait后,会自动释放锁,notify之后,要手动释放。

5.挂起(suspend)和继续执行(resume)

与stop 相反,挂起不会释放任何资源。若resume在挂起前调用了,可能持有的资源永远都不会释放了。
注意:挂起的线程,状态为Runnable

6.等待线程结束(join)

主线程会一直等待直到t1线程执行完毕。

public static void main(String[] args) {
       Thread t1 =  new Thread(()->{
           for (int i = 0;i < 100000;i ++){
               System.out.println(i);
           }
       });
       t1.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

还有一个可以指定等待时长:

public final synchronized void join(long millis) throws InterruptedException {

join的本质:

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;
            }
        }
    }

可以看到是让调用线程wait在当前线程对象实例上,当线程执行完毕后,会调用notifyAll通知所有等待的线程继续执行。
在Thread类上有个方法,当线程结束时会调用:

/**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
    private void exit() {
        if (group != null) {
            group.threadTerminated(this);
            group = null;
        }
        /* Aggressively null out all reference fields: see bug 4006245 */
        target = null;
        /* Speed the release of some of these resources */
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }

进入:threadTerminated可以看到在这里调用了notifyAll

    void threadTerminated(Thread t) {
        synchronized (this) {
            remove(t);

            if (nthreads == 0) {
                notifyAll();
            }
            if (daemon && (nthreads == 0) &&
                (nUnstartedThreads == 0) && (ngroups == 0))
            {
                destroy();
            }
        }
    }

因此:不要在Thread对象实例上使用wait或notify等方法,以被系统api影响。

7.yield

让出CPU时间片

3.volatile关键字

如果变量没有使用该关键字修饰,当修改该变量后,其他线程不一定能看到变化。

4.线程组

ThreadGroup类,可以将多个相同功能线程放入一个线程组。可以看到它里面有许多方法。
在源码中能看到:The thread groups form a tree in which every thread group except the initial thread group has a parent.
可以看出是一个树形的结构。
在这里插入图片描述

5.守护线程

在一个java应用内,当只有守护线程时,程序退出。主线程不是守护线程。
设置守护线程:

Thread t1 =  new Thread();
t1.setDaemon(true);

6.线程优先级

Thread t1 =  new Thread();
       t1.setPriority(Integer.MAX_VALUE);

7.线程安全的概念与synchronized

volatile只保证一个线程修改了数据后,其他线程能够看到变化,但多个线程同时修改时,仍然会产生冲突。
synchronized可以对代码进行加锁。

  • 指定加锁对象
  • 直接作用于实例方法:当前对象
  • 直接作用于静态方法:当前类

8.隐蔽的错误

1.并发下的ArrayList
2.并发下的HashMap
3.错误的加锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值