码迷,mamicode.com
首页 > 编程语言 > 详细

Java多线程基础

时间:2019-03-04 22:37:45      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:long   end   access   ati   死锁   inter   停止线程   同步   指正   

目录:

  1. 进程和线程
  2. 为什么使用多线程?
  3. 多线程的创建方式
  4. Runnable与Thread两种方式比较
  5. start()与run()方法
  6. 线程的生命周期/状态转换
  7. 常用方法使用与解读
  8. 线程的优先级
  9. 守护线程

1、进程和线程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

一个程序就是一个进程,而一个程序中的多个任务则被称为线程。

进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位。

2、为什么要使用多线程?

提升效率,提升性能;发挥多核CPU的优势。

防止阻塞:从程序运行效率的角度来看,单核CPU不但不会发挥出多线程的优势,反而会因为在单核CPU上运行多线程导致线程上下文的切换,而降低程序整体的效率。但是单核CPU我们还是要应用多线程,就是为了防止阻塞。试想,如果单核CPU使用单线程,那么只要这个线程阻塞了,比方说远程读取某个数据吧,对端迟迟未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止运行了。多线程可以防止这个问题,多条线程同时运行,哪怕一条线程的代码执行读取数据阻塞,也不会影响其它任务的执行。

3、多线程的创建方式[细分为5种]

  • 继承Thread类,重写run方法。new一个实例。
  • 实现Runnable接口,重写run方法。作为参数传入Thread thread = new Thread(参数);来创建。
  • 匿名内部类的方式(与实现Runnable接口一样,只是形式不同 )
  • 通过并发包中Callable、Callback来创建
  • 通过线程池来创建线程

4、Runnable与Thread两种方式比较

继承Thread不必多说,继承后重写run方法。new一个实例调用start()方法就可以了。

两者非要比较的话,使用Runnable较好,因为实现接口的方式比继承类的方式更灵活,也能减少程序之间的耦合度,面向接口编程也是设计模式6大原则的核心。

这里重点看下实现Runnable接口创建线程,实现Runnable接口实际上还是需要Thread类来创建线程,我们来看下Thread的构造方法API:

技术图片

另外需要说明的是Thread.java类也实现了Runnable接口,如下图:

技术图片

那也就意味着Thread的构造函数不仅可以传入Runnable接口的对象还可以传入一个Thread类的对象,这样就可以将一个Thread类的run()方法交由其他线程来调用。

5、start()与run()方法

只有调用了start()方法,才会表现出多线程的特性,不同线程的run()方法里面的代码交替执行。如果只是调用run()方法,那么代码还是同步执行的,必须等待一个线程的run()方法里面的代码全部执行完毕之后,另外一个线程才可以执行其run()方法里面的代码。

6、线程的生命周期/状态转换

生命周期的五种状态【简单版文字描述】:

新建(new Thread)当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();

就绪(runnable)线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();

运行(running)线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

自然终止:正常运行run()方法后终止

异常终止:调用stop()方法让一个线程终止运行,这里说明下stop()方法虽然可以停止线程,但这个方法线程不安全,在新版本的java中已经被废弃

堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

正在等待:调用wait()方法。(调用notify()方法回到就绪状态)

被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)废弃

更全的线程状态转换图如下:

技术图片

7、常用方法使用与解读

Java8在线API地址:https://docs.oracle.com/javase/8/docs/api/

start():使线程进入“就绪”(可运行)状态,通知jvm开启新线程来执行run方法。如果多次调用了start()方法,则会出现Exception in thread "main" java.lang.IllegalThreadStateException因为start会修改当前线程的状态变量,只有状态变量是初始值时才能start。


线程中断相关:

stop()【废弃】:停止一个线程,可以使用Thread.stop()方法,但是他是不安全的,而且已经被废弃了呢。调用的时候还会抛出一个java.lang.ThreadDeath异常 ,但是通常情况下,此异常不需要显示的捕捉。废弃原因:因为强制让线程停止则有可能使一些请理性的工作得不到完成。另外情况就是对锁定的对象进行了“解锁”,导致 数据得不到同步的处理,出现数据不一致的问题。

interrupt():大多数停止一个线程的操作是使用Thread.interrupt()方法,尽管名义为“中止,停止”但这个方法不会终止一个正在运行的线程,只是打了一个标记,还需要加入一个判断才可以完成线程的停止。Thread.java中提供了两个方法:

  • this.interrupted():测试当前线程是否已经中断。public static boolean interrupted()
  • this.isInterrupted():测试线程是否已经中断。public boolean isInterrupted()
  • 具体终止线程操作(来源网络):https://www.cnblogs.com/jenkov/p/juc_interrupt.html
    • 其中的return停止线程可以的,但是还是建议使用“抛异常”的方法来实现线程的停止,因为在catch块中还可以将异常上抛,使线程停止的事件得以传播。
  • 另外这两个方法的区别:
    • interrupted()无论怎么都是指正在运行的线程。而isInterrupted()就是表示指定的线程咯。
    • interrupted()会清除标记,什么意思呢?就是调用interrupt()给当前线程打一个中断标记,第一次用interrupted()会返回true但是 如果不处理,之后的调用都会返回false因为它把中断标记给清了。

暂停线程相关:

suspend()与resume()【废弃】:一个暂停线程,一个恢复线程到运行状态。suspend()会暂停线程,假如当前线程为关键数据结构加锁 这时被挂起那么锁将无法释放对其他线程来说造成死锁。同时也会因为线程的暂停出现数据不同步的现象。


currentThread():该方法返回代码段正在被那个线程调用的信息。

isAlive():判断当前线程是否处于活动的状态。活动状态是指线程已经启动尚未终止的状态。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的。

sleep():在指定毫秒内让当前正在执行的线程休眠。这个“正在执行的线程”是指this.currentThread()返回的线程。

getId():取得线程的唯一标识。这个是自动分配的,且是唯一的。

yield():放弃当前的CUP资源,将它让给其他的任务去占用CPU执行时间。但是放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。

8、线程的优先级

线程可以划分优先级,CPU优先执行优先级较高的线程对象中的任务。

设置线程的优先级使用setPriority()方法,该方法的源码如下:

/**
 * Changes the priority of this thread.
 * <p>
 * First the <code>checkAccess</code> method of this thread is called
 * with no arguments. This may result in throwing a
 * <code>SecurityException</code>.
 * <p>
 * Otherwise, the priority of this thread is set to the smaller of
 * the specified <code>newPriority</code> and the maximum permitted
 * priority of the thread's thread group.
 *
 * @param newPriority priority to set this thread to
 * @exception  IllegalArgumentException  If the priority is not in the
 *               range <code>MIN_PRIORITY</code> to
 *               <code>MAX_PRIORITY</code>.
 * @exception  SecurityException  if the current thread cannot modify
 *               this thread.
 * @see        #getPriority
 * @see        #checkAccess()
 * @see        #getThreadGroup()
 * @see        #MAX_PRIORITY
 * @see        #MIN_PRIORITY
 * @see        ThreadGroup#getMaxPriority()
 */
public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

在Java中,线程的优先级分为【1~10】10个等级,从代码中我们也能看到,如果小于1或者大于10,则会抛出

IllegalArgumentException异常。

JDK中使用三个常量来预定义线程的优先级:

 /**
  * The minimum priority that a thread can have.
  */
 public final static int MIN_PRIORITY = 1;

/**
  * The default priority that is assigned to a thread.
  */
 public final static int NORM_PRIORITY = 5;

 /**
  * The maximum priority that a thread can have.
  */
 public final static int MAX_PRIORITY = 10;

线程优先级的特性:

  • 继承性:比如A线程启动B线程,则B线程的优先级与A是一样的。设置A线程的优先级为6那么B线程也就是6。
  • 规则性:线程优先级等级差距很大的时候,谁先执行完与代码的调用顺序无关。CPU尽量将资源让给优先级比较高的线程
  • 随机性:优先级高的线程不一定每次都先执行完。优先级相近越能看出随机性。

优先级高的代码执行速度更快?

这是一个相对的问题,因为优先级高的会占用更多的时间片,相同的任务量能够更早的完成。或者说相同时间内可以完成更多的操作。但实际上CPU处理的速度是一样的。

9、守护线程

守护线程是一种特殊的线程,任何一个守护线程都是整个(没错是整个)JVM中所有非守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才能随着JVM一同结束工作。Daemon的作用就是为其他线程的运行提供便利服务,守护线程最经典的应用就是GC(垃圾回收器)。

让一个线程成为守护线程的方法是setDaemon(true);

Java多线程基础

标签:long   end   access   ati   死锁   inter   停止线程   同步   指正   

原文地址:https://www.cnblogs.com/nm666/p/10473691.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!