`
javawangzilong
  • 浏览: 55417 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

java多线程

阅读更多
Java多线程:

什么是进程?{
当前正在运行的程序。
代表一个应用程序在内存中的执行区域。
}


什么是线程(FlashGet)?{
是进程中的一个执行控制单元,执行路径。
(执行空间代码的执行者)
}

一个进程中至少有一个线程在负责控制程序的执行。
一个进程中如果只有一个执行路径,这个程序成为单线程程序。
一个进程中如果有多个执行路径时,这个程序成为多线程程序。

多线程的出现:可以有多条执行路径。让多部分代码可以完成同时执行。以提高效率。本身也是对问题的一种解决方案,比如图形界面的多个小程序同时执行。比如360,迅雷

Jvm启动是单线程还是多线程?{

Jvm的启动就是多线程程序。
其中有一个程序负责从主函数开始执行,并控制程序运行的流程。
同时为了提高效率,还启动了另一个控制单元(执行路径)专门负责堆内存中的垃圾回收,在程序正常执行的过程中,如果出现了垃圾,这时另一个负责收垃圾的线程会在不定时的时间内进行垃圾的处理。这两个程序是同时执行的。

}

负责执行正常代码的线程,称为主线程,该线程执行的代码都存放于主函数中。
负责收垃圾代码的线程,称为垃圾回收线程。该线程要执行的代码在finallize中。

如何在java中创建一个线程?{

其实java中对线程这类事物已经进行了描述,并提供了相对应的对象。
这个对象就是java.lang.Thread。

创建线程的两种方式
1.继承Thread类。
  步骤:
  1.定义类继承Thread
  2.覆盖Thread类中run方法()
  3.创建Thread类中的子类对象创建线程。
  4.调用Thread类中的start方法开启线程,并执行子类中的run方法
  特点:
  1,当类去描述事物,事物中有属性和行为。如果行为中有部分代码需要被多线程 所执,行,同时还在操作属性。就需要该类继承Thread类,产生该类的对象作为线 程对象。可是这样会导致每一个对象中都会存储一份属性数据。
  无法在多个线程中共享数据,加上静态,虽然实现了共享,但是生命周期过长。
2.如果一个类明确了自己的父类,那么就不可以继承Thread。因为java不允许类的多继承。

2.实现runnable接口。
  步骤:
1.定义类实现Runnable接口。
2.覆盖接口中的run方法。(将多线程要运行的代码定义在方法中)
3.通过Thread类创建线程对象,并将实现了runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
(为什么非要被Runnable接口的子类对象传递给你Thread类的构造函数呢?
  是因为线程对象在建立时,必须要明确自己要运行的run方法,而这个run方 法定义在了Runnable接口的子类中,所以要将该run方法所属的对象传递给 Thread类的构造函数。让线程对象建立,就知道运行那个run方法。

4.调用Thread类中的start方法,开启线程,并执行Runnable接口子类中的run方法。
特点:
  1.描述事物的类中封装了属性和行为,如果有部分代码需要被多线程所执行,
  同时还在操作属性,那么可以通过实现Runnable接口的方式。因为该方式是定义一个Runnable接口的子类对象,可以被多个线程所操作。实现了数据共享。
2.实现了Runnable接口的好处,避免了单继承的局限性。一个类如果已经有了自己的父类,不可以继承Thread类。但是该类中还有需要被多线程执行的代码。这时就可以通过在该类上功能扩展的形式。实现一个Runnable接口。

  所以创建线程时,尽量使用第二种方法。
  
创建线程的两种方式区别?



(为什么要覆盖run?
直接建立Thread类对象即可,并开启线程执行就可以了,但是虽然线程执行了,可是执行的代码是该线程默认的代码,该代码就存放在run方法中。
可是定义线程的目的是为了执行自定义的代码。
而线程的运行代码都存储在run方法中,所以只有覆盖了run方法,才可以运行自定义的内容。想要覆盖,必须要先继承。

主线程运行的代码都在main函数中,自定义的代码都在run方法中。
)

(
**
直接创建Thread类的子类对象就是创建了一个线程,如果直接调用该对象的方法。这时,底层资源并没有完成线程的创建和执行,仅仅是简单的调用对象的方法。
在内存中其实:1.堆内存中产生了一个对象,2.需要调用底层资源去创建执行路径

如果想要开启线程:需要调用start方法,该方法做了两件事
1.开启线程
2.调用线程的run方法
)
}


当创建了两个线程后的d1,d2后,这时程序就有了三个线程在同时执行。
当主函数执行完d1.start(),d2.start()后,这时三个线程同时打印,结果比较杂乱。
这是因为线程的随机性造成的。
随机性的原理是:windows中的多任务同时执行,其实就是多个应用程序在同时执行。
而每一个应用程序都有线程来负责控制的。所以window就是一个多线程的操作系统,那么cpu是负责提供程序运算的设备。cpu在某一时刻只能执行一个程序,所谓的多任务执行就多个应用程序在执行,其实是cpu通过快速切换来完成的。 只是感觉上是同时而已。

能不能真正意义上的同时执行?{
可以,多个cpu,就是现在的多核。
}

线程中的方法:
多线程的创建,为了对各个线程进行标示,系统会自动对各个线程起一个名字(thread--)
Static Thread currentThread() 获取到当前线程
String getName() 得到当前线程的名称
Vodi setName() 重新设置线程的名称

如何获取到主线程?
可以通过Thread类中的一个方法:currentThread返回当前正在执行的线程对象。
主线程的名字叫main--


在线程被创建后,可以分为临时阻塞状态,运行状态,冻结状态,消亡状态。
如果有三个线程A,B,C;当三个线程都调用start方法之后,三个线程都具备了执行资格,
处于临时阻塞状态。
当某一个线程A正在被CPU处理,说明A处于运行状态,即具备了资格,也具备了CPU的执行权。
而B,C处于临时阻塞状态,当CPU切换到B线程时,B就具备执行权,这时,A,C就处于临时阻塞状态,只具备执行资格,不具备执行权。

当一个线程被cpu执行具备了执行权,就到了运行状态,当cpu切换到其他线程开始执行的时候,刚才的线程就失去了执行权,回到了临时阻塞状态。
当一个线程调用了sleep,wait方法后,就释放了cpu的执行权,并释放了执行资格。
冻结状态结束后,表示线程重新具备了执行资格,但是不一定立刻具备执行权。
比如睡眠时间到,或者用notify方法唤醒线程。

当一个线程执行完就到了消亡状态,也可以调用stop方法让线程进行消亡。




线程安全问题:(因为线程的随机性,有可能会导致多线程在操作数据时发生数据错误的情况)
线程安全问题产生的原因:
当线程多条代码在操作同一个共享数据时,一个线程将部分代码执行完,还没有继续其他代码时,被另一个线程获取cpu执行权,这时,共享数据操作就有可能出现数据错误。
简单说:多条操作功能数据的代码被多个线程分开执行造成的。
安全问题涉及的内容:
共享数据。
是否被多条语句操作。
这也是判断多线程程序是否存在安全隐患的依据。

解决安全问题的方式:
  Java中提供了一个同步机制。
  解决原理:让多条操作共享数据的代码在某一时间段,被一个线程执行完,在执行过程中,其他线程不可以参与运算。
  
  同步格式:
  同步代码块:
  Synchronized(对象){
  需要被同步的代码
  }
  
  同步的原理:通过一个对象锁,将多条操作共享数据的代码进行了封装并加锁。只有持有这个锁的线程才有机会进入同步中的去执行,在执行期间,即使其他线程获取到执行权。因为没有获取到锁,所以只能在外面等。只有同步中的线程执行完同步代码块中的代码,
  出同步代码块时,才会释放这个锁,那么其他程序线程才有机会去获取这个锁,并只能有一个获取到而且进入到同步中。
  
  同步的好处:
  同步的出现解决了多线程的安全问题
  同步的弊端:
  因为多个线程每次都要判断这个锁,所以效率会降低。
  
  加入了同步,安全问题有可能依然存在,
  因为同步是有前提的:
  1,同步必须是有两个或两个以上的线程才需要同步
  2,必须要保证多个线程使用的是同一个锁,才可以实现多个线程被同步。
  如果出现加上同步,安全问题依然存在,就按照两个前提来排查问题。

如何查看程序中有无线程安全隐患?{
1,查看线程代码中是否有共享数据。
2,这个共享数据有没有被多条语句所操作。
}

同步代码块时用于封装代码的,函数也用于封装代码,不同之处是同步带有
锁机制。那么如果让函数这个封装体具备同步的特性。就可以取代同步代码块。
同步函数:就是在函数上加上synchronized关键字。Public synchronized void add();

那么同步函数用的哪个锁?{
  在同步代码块中用的是任意一个对象用来加锁,而同步函数中的锁用的是当前对象
  ,也就是this
}

同步函数和同步代码块的区别:{
同步代码块使用的锁可以是任意对象,
同步函数使用的锁是固定对象,this
所以一般定义同步时,建议使用同步代码块。
}

静态同步函数用的是哪个锁?{
  静态同步函数使用的锁不是this,
  因为静态函数中不可以定义this。
  
  静态随着类的加载而加载,这时有可能内容还没有该类的对象。
  但是一个类加载进内存,会先将这个类对应的字节码文件封装成对象,
  该对象的表示方式  类名.class 代表一个类字节码文件对象,
  该对象在内存是唯一的。
  
  静态同步函数使用的锁就是,该类对应的字节码文件对象,也就是类名.class
}

死锁:
死锁经常出现的状况为:同步嵌套。

class Test implements Runnable
{
private boolean flag;
Test(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(flag)
{
while(true)
{
synchronized(MyLock.locka)
{
System.out.println(Thread.currentThread().getName()+"...if......locka");
synchronized(MyLock.lockb)
{
System.out.println(Thread.currentThread().getName()+"...if......lockb");

}
}
}
}
else
{
while(true)
{
synchronized(MyLock.lockb)
{
System.out.println(Thread.currentThread().getName()+"...else..........lockb");
synchronized(MyLock.locka)
{
System.out.println(Thread.currentThread().getName()+"...else..........locka");

}
}
}
}
}

}

class MyLock
{
public static Object locka = new Object();
public static Object lockb = new Object();
}


class DeadLockTest
{
public static void main(String[] args)
{
Test t1 = new Test(true);
Test t2 = new Test(false);

Thread th1 = new Thread(t1,"小强");
Thread th2 = new Thread(t2,"旺财");

th1.start();
th2.start();
}
}

线程间通信:
Wait():让线程等待,将线程存储到一个线程池中。
Notify():唤醒被等待的线程,通常都唤醒线程池中的第一个,让被唤醒的线程处于临时阻塞状态。
notifyAll():唤醒所有的等待线程,将线程池中的所有线程都唤醒,让他们从冻结状态转到临时阻塞状态。

这三个方法用于操作线程,但是都定义在Object类中:
因为,这三个方法在使用的时候,都需要定义在同步中,要明确这些方法所操作的线程所属于锁。例如A锁被wait的线程,只能被A锁的notify方法唤醒。
所以必须要表示wait,notify方法所属的锁对象,而锁对象可以是任意的对象。可以被任意的对象调用的方法肯定定义在Object类中。

**等待唤醒机制,通常都用在同步中,因为需要锁的支持。而且必须要明确wait,notify锁作用的锁对象。

在java.util.concurren.locks包中提供了一个接口Lock。代替了synchronized。
Synchronized使用的隐式锁
Lock使用的是显示的锁。
Lock()获取锁
Unlock()释放锁

还有一个对象Condition。
该对象的出现替代了Object中的wait,notify,notifyAll这些操作监视器的方法
替代后await,signal,signalAll。

**新功能最大的好处就是在一个lock锁上可以添加多组监视器对象,这样就可以实现
本方只唤醒对方的现象。

Sleep和wait的区别?{
1,sleep方法必须指定时间
2,wait方法有重载形式,可以指定时间,也可以不指定

对于执行权和锁的操作:
1,sleep():释放执行权,不释放锁,因为肯定能恢复到临时阻塞状态
2,wait():释放执行权,释放锁,因为wait不释放锁,如果没有时间指定,那么其他线程都进行不了同步中,无法将其唤醒。

(同步中可以有多个存活的线程,但是只能有一个执行同步的代码,因为只有一个线程会持有同步锁,只有当该线程释放了锁,其他线程才有机会获取到锁,而且只能用一个线程获取到锁,继续执行。)
}

如何让线程停止?
1,使用Thread类中的stop方法。(强制结束,已过时)
2,线程执行的代码结束。

通常定义线程代码都有循环,因为需要单独开辟一个执行路径去重复很多事情。既然有循环,控制住循环,就可以结束run方法。
定义标记可以结束线程,但是如果线程在运行过程中处于了冻结状态,没有执行到标记,这时,可以通过Thread类中的interrupt方法中断线程的冻结状态。强制让其恢复到运行状态中来,就可以有机会执行标记,但是这种强制动作会发生异常。

setDeamo(boolean):可以将线程标记为后台线程。
线程分前台和后台两种。运行方式都一样都会获取cpu的执行权执行
不同的在于,结束的方式不同。
前台线程只有run方法结束,才结束。
后台线程,run方法结束,结束,还有,如果run方法没结束,而前台线程都结束了,后台线程也结束。
所以一个进程是否结束参考的是,是否还有前台线程存活,如果前台线程都结束了,那么进程也就结束了。


当有了join方法以后,该t1线程会全部执行完,其他线程才可以执行。
Join:临时加入一个线程进行执行。
例如,当主线程获取到了cpu的执行权,执行时,执行到了A线程的join方法。
这时就知道A线程要加入进来执行,那么A执行就需要cpu的执行权。而这时cpu的执行权在主线程持有,主线程会释放自己的执行权。让A线程进行执行,只有等A线程执行完以后,主线程才会执行,此时主线程就处于冻结状态。

一般使用情况:当在线程执行过程中,需要一个运算结果时,可以通过加入一个临时线程,将该结果进行运算,这时需要结果的线程处于冻结状态,当加入的线程执行完,该线程在继续执行。


分享到:
评论

相关推荐

    Java多线程设计模式上传文件

    Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式...

    java多线程读取文件

    Java多线程读大文件 java多线程写文件:多线程往队列中写入数据

    java多线程ppt

    java多线程PPT 多线程基本概念 创建线程的方式 线程的挂起与唤醒 多线程问题

    java 多线程操作数据库

    一个java 多线程操作数据库应用程序!!!

    java多线程经典案例

    java多线程经典案例,线程同步、线程通信、线程阻塞等经典案例

    Java多线程编程技术

    《Java多线程编程核心技术》建议猿友们读两遍,因为其写得没有那么抽象,第一遍有些概念不是很理解,可以先跳过并记录起来,第一遍阅读的目的主要是了解整个架构。第二遍再慢慢品味,并贯穿全部是指点来思考,并将...

    Java多线程编程实战指南(核心篇)

    Java多线程编程实战指南(核心篇) 高清pdf带目录 随着现代处理器的生产工艺从提升处理器主频频率转向多核化,即在一块芯片上集成多个处理器内核(Core),多核处理器(Multicore Processor)离我们越来越近了――如今...

    Java多线程知识点总结

    该文档总结了Java多线程相关的知识点,分享给大家,简单易懂!

    java多线程的讲解和实战

    详细的讲解了java多线程的原理,并配有代码进行实战,适合java初学者和想对多线程有进一步了解的人。

    java多线程通信图解

    一张图方便理解和掌握java 多线程之间通信的实质 java 多线程 其实就是每个线程都拥有自己的内存空间,多线程之间的通信,比例A线程修改了主内存(main方法的线程)变量,需要把A线程修改的结果同步到主线程中,...

    java多线程处理数据库数据

    java多线程处理数据库数据,使用并发包,无框架,可批量处数据库数据,进行增删改。。等等操作。

    java多线程,对多线程,线程池进行封装,方便使用

    java多线程,对多线程,线程池进行封装,方便使用

    Java多线程编程经验

    现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。 线程是指进程中的一个执行流程,一个进程中可以运行多个线程。...本文档提供Java多线程编程经验,方便广大Java爱好者研究学习Java多线程

    java多线程处理大数据

    java多线程处理大数据,可根据配置的线程数,任务去调度处理

    java多线程并发

    java多线程并发的在新窗口

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java多线程机制 9.1 Java中的线程 9.2 Thread的子类创建线程 9.3 使用Runable接口 9.4 线程的常用方法 9.5 GUI线程 9.6 线程同步 9.7 在同步方法中使用wait()、notify 和notifyAll()方法 9.8 挂起、恢复和终止线程 ...

    java多线程核心技术

    资深Java专家10年经验总结,全程案例式讲解,首本全面介绍Java多线程编程技术的专著 结合大量实例,全面讲解Java多线程编程中的并发访问、线程间通信、锁等最难突破的核心技术与应用实践 Java多线程无处不在,如...

    java多线程实现大批量数据导入源码

    java多线程实现大批量数据切分成指定份数的数据,然后多线程处理入库或者导出,线程的个数和每份数据的数量都可以控制

    java多线程查询数据库

    java多线程并发查询数据库,使用线程池控制分页,并发查询。

    java多线程模拟队列实现排队叫号

    java多线程模拟队列实现排队叫号,多线程模拟排队叫号取号 java多线程模拟队列实现排队叫号,多线程模拟排队叫号取号

Global site tag (gtag.js) - Google Analytics