Java 线程总结
来源:互联网 发布:政府软件外包项目 编辑:程序博客网 时间:2024/06/03 21:00
1.进程:是一个正在执行的中的程序。每一个进程都有一个执行顺序,该顺序是一个执行路径。或者叫一个控制单元。
2.线程:就是进程中一个独立的控制单元。线程控制着进程的的执行。
3.一个进程中至少有一个线程。
4.Java vm启动时会有一个进程java.exe。 该进程中至少有一个线程负责java程序的执行。而且,这个线程运行的代码存在在main方法中,该线程称为主线程。
5.扩展:其实更细节说明jvm,jvm启动不止一个线程。还有负责垃圾回收机制的线程。
6.多个线程同时执行,会发现每次执行的结果都不一样。因为多个线程都获取cpu的执行权。CPU执行到谁,谁就执行。明确一点,在某一时刻,只能有一个线程在运行(多核除外。)。CPU在做着快速的切换,以达到看上去同时执行的效果。
7.多线程的一个特性:随即性,谁抢到谁执行,至于执行多长,cpu说的算。
8.获取名字:getName。线程有默认的名字:Thread-编号(从0开始)。
9.设置名称:setName或者构造方法。new Thread(“name”)。子类重写构造方法,调用父类super(“name”)。
10. 多个线程公用一个对象:new Thread(Runnable target)。
11.死锁:同步中嵌套同步。
12.线程间通讯:其实就是多个线程在操作同一个资源,但是操作的动作不同。
13.Wait(),notify(),notifyAll()都使用在同步中,因为要持有监视器(锁)的线程。
14.如果某个 synchronized 方法是 static 的,那么当线程访问该方法时,它锁的并不是synchronized 方法所在的对象,而是synchronized 方法所在的对象所对应的Class 对 象,因为Java 中无论一个类有多少个对象,这些对象会对应唯一一个Class 对象,因此当线程分别访问同一个类的两个对象的两个 static,synchronized 方法时,他们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。
15. synchronized 块,写法:
synchronized(object)
{
}
表示线程在执行的时候会对object 对象上锁。
16. synchronized 方法是一种粗粒度的并发控制,某一时刻,只能有一个线程执行该synchronized 方法;synchronized 块则是一种细粒度的并发控制,只会将块中的代码同步,位于方法内、synchronized 块之外的代码是可以被多个线程同时访问到的。
17. wait 与 notify 方法都是定义在 Object 类中(因为任意方法都可以调用),而且是 final 的,因此会被所有的Java 类所继承并且无法重写。这两个方法要求在调用时线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized 方法或块当中。当线程执行了wait方法时,它会释放掉对象的锁。
18.代码中要明确哪个锁需要wait();
例如:Object.wait(),Object.notify();
19. 另一个会导致线程暂停的方法就是Thread 类的sleep 方法,它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。
20.线程池:等待线程都存在线程池当中。Notify按顺序唤醒池中的线程,一般唤醒第一个睡眠的线程。notifyAll唤醒全部线程。然后抢夺执行权。
创建线程的方式:
1.继承Thread类。
1)定义类继承Thread。
2)覆写Thread类中的run方法。目的:存储代码,让线程运行。
3)调用线程的start方法。该方法有两个作用:启动线程,调用run方法。Start为线程分配必须的系统资源、调度线程运行并执行run。
2.实现Runable接口步骤
1)定义类实现Runnable接口。
2)覆盖Runnable接口中的run方法。:存储代码。
3)通过Thread类建立线程对象。
4)将Runnable接口的子类对象作为实际参数传递Thread类的构造方法。原因:自定义的run方法所属对象是Runnable接口的子类对象。所以要让线程去指定指定对象的run方法,就必须明确该run方法所属的对象。
5)调用Thread类的static方法开启线程并调用Runnable接口子类的run方法。
实现方式和继承方式有什么区别:
1.实现方式好处:避免了单继承的局限性。在定义线程时,建立使用实现方式。
2.线程代码存放的位置不同。
3.实现方式可用于多个线程执行一个对象。(售票例子)
多线程安全问题:
问题原因:当多条语句在操作同一线程共享数据时,一个线程对多条语句只能执行了一部分,还没执行完。另一个线程参与进来执行。导致共享数据的错误。
解决办法:对多条操作共享数据的语句。只能让一个线程都执行完。在执行过程中,其他线程不可以参与进行。
1. 同步代码块:
Synchronized(对象){
需要被同步的代码块;
}
对象可以为任意对象值,当两个Synchronized语句中对象相同时,执行任意一个代码块中的内容时,另一个也不能被执行。
对象如同锁,持有锁的线程可以再同步中执行。没有锁的线程即使获得cpu的执行权,也进不去,因为没有获取锁。
2.同步函数:Synchronized修饰方法。
同步的前提:
1.必须要有两个或两个以上的线程。
2.必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
好处:解决了多线程安全问题。
弊端:多个线程需要判断锁,较为消耗资源。
如何找线程安全问题:
1.明确哪些代码是多线程运行的代码。
2.明确共享数据。
3.明确多线程运行代码中哪些语句是操作共享数据的。
JDK1.5后提供了多线程升级解决方案:
将同步Synchronized替换成现实Lock操作 。将Object中的wait、notify、notifyAll,替换成了Condition对象中await,signal,signalAll。使用时,莫忘使用finally{lock.unlock}解锁。Lock是个接口,一般使用它的实现类ReentrantLock,再由他(newCondition()方法)来获取condition对象。比较高级的是他可以唤醒不同对的condition对象对应的锁。即本方只唤醒对方操作。这样就可以唤醒指定的锁了。
停止线程:
原因:遇到特殊情况,线程处于冻结状态。读不到标记,线程无法结束。
解决办法:只有一种,让run方法结束。不能使用Thread 类的stop 方法(已过时)来终止线程的执行。
开启多线程运行,运行代码通常是循环结构。只要控制住循环结构,就可以让run方法结束,也就是线程结束。
方法1:一般要设定一个变量,在 run 方法中是一个循环,循环每次检查该变量,如果满足条件则继续执行,否则跳出循环,线程结束。
方法2:当没有指定的方式让冻结状态的线程恢复到运行状态时,此时方法1不适用。这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。
Thread类提供的方法是:interrupt();线程对象调用该方法,中断状态被清除(不是中断线程),它还将收到一个 InterruptedException。可以主线程中某处添加该方法,同时在run方法中的try catch( )中添加结束的条件(例如将flag变为false)。
关于锁的问题:
Java 中的每个对象都有一个锁或者叫做监视器(monitor),当访问某个对象的synchronized 方法时,表示将该对象上锁,此时其他任何线程都无法再去访问该synchronized 方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常), 那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized 方法。
如果一个对象有多个 synchronized 方法,某一时刻某个线程已经进入到了某个 synchronized 方法,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何synchronized 方法的。
1.为什么要覆盖run方法?
Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。也就是说,run方法的作用是存储线程要运行的代码。
2.同步函数用的是哪一个锁呢?
函数需要被对象调用。那么函数都有一个所属对象,就是this。所以同步函数的锁就是this。
3.如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证发现不是this,因为静态方法中也不可以this。静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。类名.class 该对象的类型是class。
静态的同步方法,使用的锁是该方法所在类的字节码文件对象:
类名.class。
4.为什么这些操作线程的方法(wait,notify,notifyAll)要定义在Object类中?
因为这些方法在操作同步线程时,都必须要标识他们所操作线程锁,只有同一个锁上的等待线程,可以被同一个锁notify唤醒。不可以对不同锁中的线程进行唤醒。也就是说,等待和唤醒的必须是同一锁。而锁可以使任意对象,所以可以被任意对象调用的方法定义Object类中。
5.对于多个生产者和消费者。
1)为什么要定义while判断标记。
原因:让被唤醒的线程再一次判断标记。
2)为什么要定义notifyAll。
原因:因为需要唤醒对方线程。而只有notify,容易出现只唤醒本方线程的情况。While循环判断导致程序中的所有线程都等待。(只唤醒一个线程,不能确定是哪方的。)
1.static Thread currentThread():返回对当前正在执行的线程对象的引用。
2.String getName() :获取线程名称。
3.Void setName(String name):设置名称。
4.Static void sleep(long millis):睡眠。(会抛异常,要捕获)
5. final void setDaemon(boolean on):将该线程标记为守护线程或后台线程,用户线程。当正在运行的线程都是守护线程时,即前台线程全部结束时,java虚拟机退出 。该方法必须在启动线程前调用。(主线程是前台线程)。
6. Void jion():当A线程执行到了B线程.jion()方法时,A就会等待。等B线程都执行完,A才会执行。Jion可以用来临时加入线程执行。
7.String toString():返回该线程的字符串表示形式,包括线程名称,优先级,线程组。
8.Void setPriority(int newPriority):设置优先级。MAX_PRIORITY,MIN_PRIORITY,NORM_PRIORITY
9. Static void yield():暂停当前正在执行的线程对象,并执行对其他线程。
1. 创建状态
• 当用new操作符创建一个新的线程对象时 ,该线程处于创建状态。
• 处于创建状态的线程只是一个空的线程对象,系统不为它分配资源 。
2. 可运行状态
• 执行线程的start()方法将为线程分配必须的系统资源,安排其运行,并调用线程体 —run()方法,这样就使得该线程处于可运行( Runnable )状态。这一状态并不是运行中状态(Running ) ,因为线程也许实际上并未真正运行。
3.不可运行状态
当发生下列事件时,处于运行状态的线程会转入到不可运行状态。
• 调用了sleep ()方法;
• 线程调用wait方法等待特定条件的满足
• 线程输入/输出阻塞
返回可运行状态:
处于睡眠状态的线程在指定的时间过去后,或者线程在等待某一条件,另一个对象必须通过notify()或notifyAll()方法通知等待线程条件满足。还有就是线程是因为输入/输出阻塞,等待输入/输出完成
4. 消亡状态当线程的run方法执行结束后,该线程自然消亡。
1. 线程的优先级及其设置
设置优先级是为了在多线程环境中便于系统对线程的调度,优先级高的线程将优先执行。
一个线程的优先级设置遵从以下原则:
– 线程创建时,子继承父的优先级
– 线程创建后,可通过调用setPriority()方法改变优先级。
– 线程的优先级是1-10之间的正整数。
1 - MIN_PRIORITY,
10 – MAX_PRIORITY
5- NORM_PRIORITY
2.线程的调度策略
线程调度器选择优先级最高的线程运行。但是,如果发生以情况,就会终止线程的运行。
• 线程体中调用了yield()方法,让出了对CPU的占用权
• 线程体中调用了sleep()方法, 使线程进入睡眠状态
• 线程由于I/O操作而受阻塞
• 另一个更高优先级的线程出现。
• 在支持时间片的系统中,该线程的时间片用完。
Thread 的一些常用方法。
• 测试 threads:
isAlive()
• Thread priority:
t getPriority()
t setPriority()
• threads 进入非执行状态
Thread. sleep()
Thread. yield()
同步机制:
1.为什么要引入同步机制
在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源。必须对这种潜在资源冲突进行预防。
解决方法:在线程使用一个资源时为其加锁即可。访问资源的第一个线程为其加上锁以后,其他线程便不能再使用 那个资源,除非被解锁。
2.怎样实现同步
对于访问某个关键共享资源的所有方法,都必须把它们设为synchronized
例如:
synchronized void f() { /* ... */ }
synchronized void g() { /* ... */ }
如果想保护某些资源不被多个线程同时访问,可以强制通过synchronized方法访问那些资源。调用synchronized方法时,对象就会被锁定。
说明:
• 当synchronized方法执行完或发生异常时,会自动释放锁。
• 被synchronized保护的数据应该是私有(private)的。
线程组:
所有线程都隶属于一个线程组。那可以是一个默认线程组,亦可是一个创建线程时明确指定的组。
说明:
在创建之初,线程被限制到一个组里,而且不能改变到一个不同的组。
若创建多个线程而不指定一个组,它们就会与创建它的线程属于同一个组。
- Java线程总结
- Java线程总结
- Java线程总结
- java线程学习总结
- 【转】Java线程总结
- Java语法总结 - 线程
- Java线程总结
- Java线程总结
- Java线程总结
- Java线程总结
- Java语法总结 - 线程
- Java线程:大总结
- Java线程:大总结
- Java线程总结
- java线程安全总结
- Java线程总结
- java线程安全总结
- Java线程总结
- Linux系统日志管理
- hdu Employment Planning (dp)
- 总结c++的“编译、链接”时引发的血案——动态、静态链接库
- 驱动笔记
- 总结extern “C”时引发的血案——c++的“编译、链接”原理与过程
- Java 线程总结
- extern “C”再次总结
- java实现冒泡,插入,选择排序
- Android中资源文件夹:res/raw和assets
- 可悲呀,可悲!!!这就是我们目前的高等教育
- barebox简要分析
- 条件变量(Condition Variable)详解
- sencha touch中实现页面之间的互相跳转
- 用java实现简单的网络通信,相当于一个最简单的控制台qq(附代码)