【Java笔记】——如何理解线程
来源:互联网 发布:网络用语打call的意思 编辑:程序博客网 时间:2024/06/14 04:16
上篇文章说道在Java中,“流”是抽象的概念,不容易理解。而所谓的进程和线程,同样也是看不到摸不着的,同样属于抽象概念。但是把进程和线程形象化之后,就会发现,其实两者有很大的区别。
简单理解进程和线程,现在的操作系统都是多任务操作系统,可以同时运行很多应用程序,进程就是内存中一个正在运行的应用程序,它有自己独立的内存空间,而且可以启动多条线程。比如现在有一个支持多用户登录的系统,系统启动是一个进程,而多个人登录就是多个线程,这样理解起来就方便多了。
概念
线程是一个程序内部的顺序控制流,Java中的线程是通过java.lang.Thread类来实现的。
创建和启动
线程的创建可以有两种方式,第一种是定义的线程类实现Runnable接口
<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">public class TestThread{public static void main(String args[]){Runner r=new Runner();Thread t=new Thread(r);t.start(); //启动线程for(int i=0;i<100;i++){System.out.println("Main Thread:---------"+i);}}}class Runner implements Runnable{public void run(){for(int i=0;i<100;i++){System.out.println("Runner:"+i);}}}</span></span></span></span>
第二种是定义一个Thread的子类,并重写其run()方法
<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">public class TestThread{public static void main(String args[]){Runner r=new Runner();r.start(); //启动线程for(int i=0;i<100;i++){System.out.println("Main Thread:---------"+i);}}}class Runner extends Thread{public void run(){for(int i=0;i<100;i++){System.out.println("Runner:"+i);}}}</span></span></span></span>
线程同步
什么是线程同步?在实际应用中,会有这样的情况,两个线程同时对相同数据进行操作,这样就会产生问题,会导致两个线程都的不到自己满意的返回数据,解决这个问题的方法就是线程同步。
线程同步就是给数据加锁,在一个线程访问当前对象时,给当前对象加锁,执行完成后解锁,然后另一个线程才能进行访问。不过加锁之后,并不能解决一切问题,因为这样会引起“死锁”。
死锁是当多个进程需要同时访问多个对象时会引起的问题,下面看一个小例子:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">public class TestDeadLock implements Runnable {public int flag = 1;static Object o1 = new Object(), o2 = new Object();public void run() {System.out.println("flag=" + flag);if(flag == 1) { //当flag=1时,对象o1加锁,只允许一个线程访问synchronized(o1) {try {Thread.sleep(500); //线程睡眠半秒钟} catch (Exception e) {e.printStackTrace();}synchronized(o2) { //访问对象o2,并对o2加锁System.out.println("1");}}}if(flag == 0) { //当flag=0时,对象o2加锁,只允许一个线程访问synchronized(o2) {try {Thread.sleep(500); //线程睡眠半秒钟} catch (Exception e) {e.printStackTrace();}synchronized(o1) { //访问对象o1,并对o1加锁System.out.println("0");}}}}public static void main(String[] args) {TestDeadLock td1 = new TestDeadLock(); TestDeadLock td2 = new TestDeadLock(); td1.flag = 1; td2.flag = 0; Thread t1 = new Thread(td1); //线程1,且flag为1Thread t2 = new Thread(td2); //线程2,且flag为0t1.start(); //线程1启动,此时flag为1,访问对象o1并加锁t2.start(); //线程2启动,此时flag为0,访问对象o2并加锁}}</span></span></span></span>
线程1和线程2都需要对象o1和o2才能完成,如代码中所示,线程1的flag为1,所以此时正访问对象o1,并且锁定了对象o1,而它再需要访问对象o2就能完成任务。同样线程2也是这样,它的flag为0,此时正访问对象o2,并且锁定了对象o2,再需要访问对象o1就能完成任务。而此时的问题是,两者都没有完成任务,所以都不释放当前锁定的对象,而且都需要对方锁定的对象,这是就产生了死锁。
总结
线程是轻量级的进程,如果一个进程只有一个线程,就好像一个饭店只有一个厨师,在一定情况下是不符合实际的,这也就有了多线程。但是,多线程中的死锁问题是很容易出现的,原因就在于锁的设置不合理,只要在项目中合理的设置锁的位置,死锁问题还是可以避免的。
- 【Java笔记】——如何理解线程
- java——简单理解线程
- Java守护线程的理解笔记
- 深入理解java线程池—ThreadPoolExecutor
- 深入理解java线程池—ThreadPoolExecutor
- 深入理解java线程池—ThreadPoolExecutor
- 深入理解java线程池—ThreadPoolExecutor
- 深入理解java线程池—ThreadPoolExecutor
- java基础—如何创建线程?如何保证线程安全?
- Java基础——深入理解Java线程池
- 深入理解java虚拟机—java内存模型与线程
- Java与线程(深入理解Java虚拟机学习笔记)
- Java线程安全(深入理解Java虚拟机学习笔记)
- Java语言中的线程安全--《深入理解Java虚拟机》笔记
- CPU核心数与线程数的理解——java并发编程入门到精通笔记
- 如何理解线程
- 如何理解线程
- Java多线程——如何中断线程
- 【DP】 HDOJ 4804 Campus Design
- ReactiveCocoa的举例
- Jboss5.1 安装
- iOS开发之 UITextField
- 数据结构例程——单链表应用举例
- 【Java笔记】——如何理解线程
- Codeforces Round #319 (Div. 1) div1 A B C
- android.os.NetworkOnMainThreadException错误解决办法
- C++_递归习题汇总
- Codeforces Round #319 (Div. 1) B. Invariance of Tree
- 视觉感觉生命分析
- loadView、viewDidLoad及viewDidUnload的关系
- Cocos2d-x的ClippingNode的最简要使用方法
- deepin 设置su 密码