java线程学习笔记
来源:互联网 发布:笔记本防护软件 编辑:程序博客网 时间:2024/05/29 08:36
一、线程和进程
关于线程和进程的关系:进程是一个一个单独运行的程序,一个进程就是一个独立的执行环境。进程有着完整的,私有的基本的运行时资源,尤其是每个进程都有自己的内存空间而线程是进程中的一个工作流。比如QQ,就是一个进程,但是打开QQ之后可以和很多个人聊天、视频、传递文件等等操作,这就是一个一个的线程。
二、线程的状态
线程的4中状态:新建状态(new)、可执行状态(runnable)、阻塞状态(blocked)、死亡状态(dead)
新建状态:线程已经创建,但是还没开始执行,尚未被调用,没有执行start()方法;
可执行状态:线程对象执行了start()方法,在线程池中等待cpu分配时间片段开始执行;
阻塞状态:一个运行中的线程通过wait(),sleep()等方法,有运行状态变成停滞状态就是阻塞状态,使用wait()方法使线程进入阻塞状态,可通过调用notify()或者notifyAll()方法唤醒 进入执行状态,sleep()方法在睡眠时间结束之后自动进入可执行状态;(wait是Object的方法,sleep是线程的方法)
死亡状态:一个线程正常结束之后就处于死亡状态;
三、线程的实现
实现线程一般有两种方法:一种是直接继承Thread类,一种就是实现Runnable接口;
继承Thread的方式:
public class Demo extends Thread{
public void run(){
System.out.println("this is extends Thread");
}
public static void main(String[] args){
Thread t = new Demo();
t.start();
}
}
实现Runnable的方式:
public class Demo implements Runnable{
public void run(){
System.out.println("this is implements Runnable");
}
public static void main(String args[]){
Runnable r = new Demo();
Thread t = new Thread(r);
t.start();
}
}
由于java不支持多继承,所以一般创建一个线程都是实现Runnable接口
四、终止线程的方法
一般终止线程有3中方法:一是自动终止,在程序执行结束之后线程就会自动终止;二是调用stop()方法强制终止线程;三是使用interrupt方法终止线程
1)public class Demo implements Runnable{
public volatile boolean exit = false;
public void run(){
while(!exit);
}
public static void main(String args[]) throws Exception{
Demo r = new Demo();
Thread t = new Thread(r);
t.start();
t.sleep(5000);//主线程延迟5s
r.exit = true;//终止线程
}
}
/**定义了一个退出标志exit,当exit为true时,while退出循环;定义exit的时候使用了volatile关键字,目的是为了使exit同步,在同一时刻只能由一个线程来修改exitd的值 */
2)使用stop()方法强制退出:t.stop()
/**不推荐使用stop方法,使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。*/
3)public class Demo extends Thread
{
public void run()
{
try
{
sleep(50000); // 延迟50秒
}
catch (InterruptedException e)
{
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws Exception
{
Thread t = new Demo();
t.start();
System.out.println("在50秒之内按任意键中断线程!");
System.in.read();
t.interrupt();
System.out.println("线程已经退出!");
}
}
/**
在调用interrupt方法后, sleep方法抛出异常,然后输出错误信息:sleep interrupted.
注意:在Thread类中有两个方法可以判断线程是否通过interrupt方法被终止。一个是静态的方法interrupted(),一个是非静态的方法isInterrupted(),这两个方法的区别是interrupted用来判断当前线是否被中断,而isInterrupted可以用来判断其他线程是否被中断。因此,while (!isInterrupted())也可以换成while (!Thread.interrupted())。
*/五、wait()和sleep()的区别
wait:使一个线程处于等待状态,并且释放所持有的对象的lock;
sleep:使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉interruptException异常
notify:唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notifyAll:唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争
关于线程的同步,先区别一下wait()和sleep()的区别
1)这两个方法来自不同的类,wait()方法来自Thread而sleep()来自于Object
2)最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法
3)wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)
4)sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常(使用sleep方法后,不会释放所持有的对象锁,但有可能被其他对象调用它的interrupt()方法,产生
interruptException异常,如果不捕获这个异常,线程就会意外终止)
六、线程同步
同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果;同步的实现有两种方式:同步方法和同步代码块,使用关键字synchronized
给一个方法添加synchronized修饰之后就可以使他成为同步方法,这个方法可以是静态的也可以是非静态的,但是不能是抽象类的抽象方法,也不能是接口中的接口方法
public void synchronized Method(){
//do somthing
}
public static synchronized void Method(){
//do somthing
}
线程在执行同步方法时是具有排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。
同步代码块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;而同步方法是对这个方法块里的代码进行同步,而这种情况下锁定的对象就是同步方法所属的主体对象自身。如果这个方法是静态同步方法呢?那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,所以静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。
如果一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法,也不能执行同步块
synchronized的目的是使同一个对象的多个线程,在某个时刻只有其中的一个线程可以访问这个对象的synchronized 数据
public class ThreadTest implements Runnable{
public synchronized void run(){
for(int i=0;i<10;i++) {
System.out.print(" " + i);
}
}
public static void main(String[] args) {
Runnable r1 = new ThreadTest(); //也可写成ThreadTest r1 = new ThreadTest();
Runnable r2 = new ThreadTest();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}}
示例2:public class ThreadTest implements Runnable{
public synchronized void run(){
for(int i=0;i<10;i++){
System.out.print(" " + i);
}
}
public static void main(String[] args){
Runnable r = new ThreadTest();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}}
示例3:
public class ThreadTest implements Runnable{
public void run(){
synchronized(this){
for(int i=0;i<10;i++){
System.out.print(" " + i);
}} }
public static void main(String[] args){
Runnable r = new ThreadTest();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}}
示例1,虽然同步了run()方法,但是保护的不是共享数据,因为是两个对象的线程,而不同对象的数据是不同的示例2,使用synchronized修饰了run()方法, 保护的是同一个对象的共享数据,输出的数据总是为0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
示例3,效果跟示例2一样,在可能的情况下,应该把保护范围缩到最小
- java线程学习笔记
- java线程学习笔记
- java 线程 学习笔记
- java线程学习笔记
- java线程学习笔记
- Java线程学习笔记
- java线程学习笔记
- JAVA学习笔记 -- 线程
- JAVA学习笔记 -- 线程
- Java 线程学习笔记
- 学习笔记-java线程
- 【Java学习笔记】线程
- Java学习笔记: 线程
- java线程学习笔记
- java学习笔记-线程
- JAVA线程学习笔记
- Java学习笔记--线程
- Java学习笔记--线程
- Why the volume so big after coping file from Linux to Windows?
- linux su userName和su - userName 的区别
- C# FTP/SSL控件移动设备版FTP/SSL for .NET/.NET CF控件详细介绍
- CocoaPods
- 爱加密免费apk漏洞检测 、遏制手机App遭到反编译。
- java线程学习笔记
- 媒体查询
- linux下DISPLAY和xhost + 作用
- Android中关于JNI 的学习(三)在JNI层访问Java端对象
- 从两个TIMESTAMP中获取时间差(秒)
- Vim 设置以及解决中文乱码
- Linux CentOS下安装、配置mysql数据库
- 检测app版本
- servlet工作原理解析