java多线程解说【壹】_什么是线程

这是新的系列的一篇文章。争取好好写。争取这个星期边复习边写,可以写完这个系列。


这个系列就是java多线程。


进程和线程


这两个名词从字面上看相当容易混淆,感觉都是程字辈的。实则不然。如果对其概念加以了解,那么区分开来就相当容易。进程就是程序运行的实例,可以认为是正在进行的程序。而线程则是进程中可以独立执行的最小单位,线程要完成的计算称为任务。


举个例子,我们在windows系统点击"任务管理器",切换到任务选项卡下所展示的列表就是一个个的进程。而一个进程可能在同时处理多个任务,这就需要多个线程去处理。所以在线程数一列展示出,基本上一个进程都开启了多个线程在处理任务。(如下图)




在java语言里,当我们运行一个main函数时,其实这个main函数就是一个单独的线程。当然,java虚拟机运行起来的时候,还会有其他守护线程和GC线程,这个我们先不讨论。我们也可以在代码里显式地声明一个线程,通常有两种方式:一是让该类继承Thread类,二是让该类实现Runnable接口。不管通过哪种方式,都需要重写run方法。


线程的生命周期




如上图所示,当我们创建了一个线程实例并调用其start方法后,这个线程就进入了就绪状态。注意,此时它并没有马上开始执行,它具体的执行时间由java虚拟机中的线程调度器(scheduler)决定,什么时候调度到这个线程,这个线程才会开始执行并进入运行状态。当线程在运行的时候,有可能因为没有获取到需要资源的锁而进入阻塞状态,也有可能根据业务需要进行了休眠(Thread.sleep())和等待(Object.wait())而进入了等待状态,根据是否设置了等待时间,等待状态可分为限时等待(TIMED WAITING)和永久等待(WAITING)。当线程运行结束后,便进入终止状态,等待回收。


这里有一点需要注意,我们可以调用Thread.start()方法去启动一个线程,也可以通过直接执行run()方法去启动。那么这两种方法有什么不同呢?其实看源码,start()方法内部也是调用的run()方案,但是有一点区别,start()会创建一个新的线程实例,并在新的实例里去执行run();而如果手动直接执行run()方法的话,则是相当于在当前线程中运行。可通过下面的测试代码运行见不同之处:


public static void main(String[] args) {
		Thread thread = new Thread(){
            @Override
            public void run() {
                System.out.println("1:" + Thread.currentThread().getName());
            }
        };
        thread.start();
        thread.run();
	}


线程的分类


Java中线程分为守护线程(Daemon Thread)和用户线程(User Thread)。用户线程会阻止JVM正常停止,即当所有用户线程停止后,JVM才会停止;而守护线程不会,它只是做一些监视其他线程等重要性不高的任务。


子线程是在父线程中启动的线程。如果父线程是守护/用户线程,则子线程则也是守护/用户线程


线程的安全问题


线程的安全问题包括原子性、可见性和有序性:


原子性:一个操作或多个操作要么全部执行完成且执行过程不被中断,要么就不执行。

可见性:当多个线程同时访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

有序性:程序执行的顺序按照代码的先后顺序执行。


在单线程下,这三个特性就没有问题;但是在多线程下,由于可能产生竞态条件,因此我们需要采取一些措施来保证线程的安全问题。那么我们如果做呢,请看下文:


java多线程解说【贰】_java内存模型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值