JAVA多线程java
多线程的基本概念算法
线程指进程中的一个执行场景,也就是执行流程,那么进程和线程有什么区别呢?编程
• 每一个进程是一个应用程序,都有独立的内存空间windows
• 同一个进程中的线程共享其进程中的内存和资源(共享的内存是堆内存和方法区内存,栈内存不共享,每一个线程有本身的。)安全
什么是进程?多线程
一个进程对应一个应用程序。例如:在windows操做系统启动Word就表示启动了一个并发
进程。在java的开发环境下启动JVM,就表示启动了一个进程。现代的计算机都是支持多异步
进程的,在同一个操做系统中,能够同时启动多个进程。ide
多进程有什么做用?异步编程
单进程计算机只能作一件事情。
玩电脑,一边玩游戏(游戏进程)一边听音乐(音乐进程)。
对于单核计算机来说,在同一个时间点上,游戏进程和音乐进程是同时在运行吗?不是。
由于计算机的CPU只能在某个时间点上作一件事。因为计算机将在“游戏进程”和“音乐
进程”之间频繁的切换执行,切换速度极高,人类感受游戏和音乐在同时进行。
多进程的做用不是提升执行速度,而是提升CPU的使用率。
进程和进程之间的内存是独立的。
什么是线程?
线程是一个进程中的执行场景。一个进程能够启动多个线程。
多线程有什么做用?
多线程不是为了提升执行速度,而是提升应用程序的使用率。
线程和线程共享“堆内存和方法区内存”,栈内存是独立的,一个线程一个栈。
能够给现实世界中的人类一种错觉:感受多个线程在同时并发执行。
java程序的运行原理?
java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,表示启动了一个进程。该进程会自动启动一个“主线程”,而后主线程去调用某个类的main方法。因此main方法运行在主线程中。在此以前的全部程序都是单线程的。
线程生命周期
线程是一个进程中的执行场景,一个进程能够启动多个线程
新建:采用new语句建立完成
就绪:执行start后
运行:占用CPU时间
阻塞:执行了wait语句、执行了sleep语句和等待某个对象锁,等待输入的场合
终止:退出run()方法
多线程不是为了提升执行速度,而是提升应用程序的使用率.
线程和线程共享”堆内存和方法区内存”.栈内存是独立的,一个线程一个栈.
能够给现实世界中的人类一种错觉:感受多线程在同时并发执行.
不少人都对其中的一些概念不够明确,如同步、并发等等,让咱们先创建一个数据字典,以避免产生误会。
• 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
• 并行与并发:
•
o 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
•
o 并发:经过cpu调度算法,让用户看上去同时执行,实际上从cpu操做层面不是真正的同时。并发每每在场景中有公用的资源,那么针对这个公用的资源每每产生瓶颈,咱们会用TPS或者QPS来反应这个系统的处理能力。
线程安全:常常用来描绘一段代码。指在并发的状况之下,该代码通过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,咱们只须要关注系统的内存,cpu是否是够用便可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转帐代码:
voidtransferMoney(Userfrom,Userto,floatamount){
to.setMoney(to.getBalance()+amount);
from.setMoney(from.getBalance()-amount);
}
同步:Java中的同步指的是经过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提升性能,才是优秀的程序。线程安全的优先级高于性能。
Java命令会启动Java虚拟机,启动JVM,等于启动了一个应用程序,表示启动了一个进程,该进程会自动启动一个”主线程”,
而后主线程去调用某个类的main()方法,因此main()方法运行在主线程中.
线程的调度与控制
线程的调度模型分为:分时调度模型和抢占式调度模型,Java使用抢占式调度模型
一般咱们的计算机只有一个CPU,CPU在某一个时刻只能执行一条指令,线程只有获得CPU时间片,也就是使用权,才能够执行指令。在单CPU的机器上线程不是并行运行的,只有在多个CPU上线程才能够并行运行。Java虚拟机要负责线程的调度,取得CPU的使用权,目前有两种调度模型:分时调度模型和抢占式调度模型,Java使用抢占式调度模型。分时调度模型:全部线程轮流使用CPU的使用权,平均分配每一个线程占用CPU的时间片抢占式调度模型:优先让优先级高的线程使用CPU,若是线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些。
分时调度模型:全部线程轮流使用CPU的使用权,平均分配每一个线程占用CPU的时间片
抢占式调度模型:优先让优先级高的线程使用CPU,若是线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些.
publicclassThreadTest{
publicstaticvoidmain(String[]args){
ThreadTest1();
//ThreadTest2();
//ThreadTest3();
//ThreadTest4();
//ThreadTest5();
}
/**
*三个方法:获取当前线程对象:Thread.currentThread();给线程起名:t1.setName("t1");获取线程的名字:
*t.getName();
*/
privatestaticvoidThreadTest1(){
Threadt=Thread.currentThread();//t保存的内存地址指向的线程为"主线程"
System.out.println(t.getId());
Threadt1=newThread(newProcessor1());
//给线程起名
t1.setName("t1");
t1.start();
Threadt2=newThread(newProcessor1());
t2.setName("t2");
t2.start();
}
/**
*线程优先级高的获取的CPU时间片相对多一些优先级:1-10最低:1最高:10默认:5
*/
privatestaticvoidThreadTest2(){
Threadt1=newProcessor2();
Threadt2=newProcessor2();
t1.setName("t1");
t2.setName("t2");
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
/**
*1.Thread.sleep(毫秒);2.sleep方法是一个静态方法3.该方法的做用:阻塞当前线程,腾出CPU,让给其它线程
*/
privatestaticvoidThreadTest3(){
Threadt=newThread(newProcessor3());
t.start();
for(inti=0;i<11;i++){
System.out.println(Thread.currentThread().getName()+"========>"
+i);
try{
t.sleep(5000);//等同于Thread.sleep(5000);阻塞的仍是当前线程,和t线程无关.
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
/**
*某线程正在休眠,如何打断它的休眠如下方式依靠的是异常处理机制
*/
privatestaticvoidThreadTest4(){
try{
Threadt=newThread(newProcessor4());
t.start();
Thread.sleep(5000);//睡5s
t.interrupt();//打断Thread的睡眠
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
/**
*如何正确的更好的终止一个正在执行的线程需求:线程启动5s以后终止.
*/
privatestaticvoidThreadTest5(){
Processor5p=newProcessor5();
Threadt=newThread(p);
t.start();
//5s以后终止
try{
Thread.sleep(5000);
p.isRun=false;
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
classProcessor1implementsRunnable{
publicvoidrun(){
Threadt=Thread.currentThread();//t保存的内存地址指向的线程为"t1线程对象"
System.out.println(t.getName());
System.out.println(t.getId());
}
}
classProcessor2extendsThread{
publicvoidrun(){
for(inti=0;i<50;i++){
System.out.println(Thread.currentThread().getName()
+"----------->"+i);
}
}
}
classProcessor3implementsRunnable{
/**
*Thread中的run方法不能抛出异常,因此重写runn方法以后,在run方法的声明位置上不能使用throws
*因此run方法中的异常只能try...catch...
*/
publicvoidrun(){
for(inti=0;i<11;i++){
System.out.println(Thread.currentThread().getName()+"========>"
+i);
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
classProcessor4implementsRunnable{
publicvoidrun(){
try{
Thread.sleep(1000000000);
System.out.println("可否执行这里");
}catch(InterruptedExceptione){
e.printStackTrace();
}
for(inti=0;i<11;i++){
System.out.println(Thread.currentThread().getName()+"========>"
+i);
}
}
}
classProcessor5implementsRunnable{
booleanisRun=true;
@Override
publicvoidrun(){
for(inti=0;i<11;i++){
if(isRun){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+"========>"+i);
}
}
}
}
线程优先级
线程优先级主要分三种:MAX_PRIORITY(最高);MIN_PRIORITY(最低级)NORM_PRIORITY(标准)默认
//设置线程的优先级,线程启动后不能再次设置优先级
//必须在启动前设置优先级
//设置最高优先级
t1.setPriority(Thread.MAX_PRIORITY);
sleep
publicclassSleepTest{
publicstaticvoidmain(String[]args){
System.out.println("Wait");
//让主线程等待5秒再执行
Wait.bySec(5);
//提示恢复执行
System.out.println("start");
}
}
classWait{
publicstaticvoidbySec(longs){
//sleeps个1秒
for(inti=0;i<s;i++){
System.out.println(i+1+"秒");
try{
//sleep1秒
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
中止一个线程
若是咱们的线程正在睡眠,能够采用interrupt进行中断
一般定义一个标记,来判断标记的状态中止线程的执行
yield
它与sleep()相似,只是不能由用户指定暂停多长时间,而且yield()方法只能让同优先级的线程有执行的机会,采用yieid能够将CPU的使用权让给同一个优先级的线程
publicclassYieldTest{
publicstaticvoidmain(String[]args){
FirstThreadmt=newFirstThread();
SecThreadmnt=newSecThread();
mt.start();
mnt.start();
}
}
classFirstThreadextendsThread{
publicvoidrun(){
for(inti=0;i<5;i++){
System.out.println("第一个线程的第"+(i+1)+"次运行");
Thread.yield();//暂停线程
}
}
}
classSecThreadextendsThread{
publicvoidrun(){
for(inti=0;i<5;i++){
System.out.println("第二个线程的第"+(i+1)+"次运行");
Thread.yield();
}
}
}
join
当前线程能够调用另外一个线程的join方法,调用后当前线程会被阻塞再也不执行,直到被调用的线程执行完毕,当前线程才会执行
publicclassJoinTestextendsThread{
publicJoinTest(Stringname){
super(name);
}
publicvoidrun(){
for(inti=0;i<5;i++)
System.out.println(getName()+""+i);
}
publicstaticvoidmain(String[]args){
for(inti=0;i<10;i++){
if(i==5){
JoinTesttempjt=newJoinTest("半路加入的线程");
try{
tempjt.start();
tempjt.join();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+""+i);
}
}
}
synchronized
线程同步,指某一个时刻,指容许一个线程来访问共享资源,线程同步实际上是对对象加锁,若是对象中的方法都是同步方法,那么某一时刻只能执行一个方法,采用线程同步解决以上的问题,咱们只要保证线程一操做s时,线程2不容许操做便可,只有线程一使用完成s后,再让线程二来使用s变量
• 异步编程模型:t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁.
• 同步编程模型:t1线程和t2线程执行,t2线程必须等t1线程执行结束以后,t2线程才能执行,这是同步编程模型.
•
• 何时要用同步呢?为何要引入线程同步呢?
• 1.为了数据的安全,尽管应用程序的使用率下降,可是为了保证数据是安全的,必须加入线程同步机制.
• 线程同步机制使程序变成了(等同)单线程.
• 2.什么条件下要使用线程同步?
• 第一:必须是多线程环境
• 第二:多线程环境共享同一个数据.
• 第三:共享的数据涉及到修改操做.
//synchronized是对对象加锁
//采用synchronized同步最好只同步有线程安全的代码
//能够优先考虑使用synchronized同步块
//由于同步的代码越多,执行的时间就会越长,其余线程等待的时间就会越长
//影响效率
publicclassTestWithdrawal{
publicstaticvoidmain(String[]args){
//建立两个线程
TestAccountr=newTestAccount();
Threadone=newThread(r);
Threadtwo=newThread(r);
one.setName("张三");
two.setName("张三的妻子");
//启动线程
one.start();
two.start();
}
}
classAccount{
privateintbalance=500;//余额
publicintgetBalance(){
returnbalance;
}
//取款
publicvoidwithdraw(intamount){
balance=balance-amount;
}
}
classTestAccountimplementsRunnable{
//全部用TestAccount对象建立的线程共享同一个账户对象
privateAccountacct=newAccount();
publicvoidrun(){
for(inti=0;i<5;i++){
makeWithdrawal(100);//取款
if(acct.getBalance()<0){
System.out.println("帐户透支了!");
}
}
}
privatevoidmakeWithdrawal(intamt){
synchronized(acct){
if(acct.getBalance()>=amt){
System.out.println(Thread.currentThread().getName()+"准备取款");
try{
Thread.sleep(500);//0.5秒后实现取款
}catch(InterruptedExceptionex){
}
//若是余额足够,则取款
acct.withdraw(amt);
System.out.println(Thread.currentThread().getName()+"完成取款,余额:"+acct.getBalance());
}else{
//余额不足给出提示
System.out.println("余额不足以支付"
+Thread.currentThread().getName()+"的取款,余额为"
+acct.getBalance());
}
}
}
}
死锁
publicclassDeadLock{
publicstaticvoidmain(String[]args){
Objecto1=newObject();
Objecto2=newObject();
Threadt1=newThread(newT1(o1,o2));
Threadt2=newThread(newT2(o1,o2));
t1.start();
t2.start();
}
}
classT1implementsRunnable{
Objecto1;
Objecto2;
T1(Objecto1,Objecto2){
this.o1=o1;
this.o2=o2;
}
@Override
publicvoidrun(){
synchronized(o1){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
synchronized(o2){
}
}
}
}
classT2implementsRunnable{
Objecto1;
Objecto2;
T2(Objecto1,Objecto2){
this.o1=o1;
this.o2=o2;
}
@Override
publicvoidrun(){
synchronized(o2){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
synchronized(o1){
}
}
}
}
守护线程
从线程分类上能够分为:用户线程(以上讲的都是用户线程),另外一个是守护线程。守护线程是这样的,全部的用户线程结束生命周期,守护线程才会结束生命周期,只要有一个用户线程存在,那么守护线程就不会结束,例如java中著名的垃圾回收器就是一个守护线程,只有应用程序中全部的线程结束,它才会结束。
• 其它全部的用户线程结束,则守护线程退出!
• 守护线程通常都是无限执行的.
publicclassDaemonThread{
publicstaticvoidmain(String[]args)throwsInterruptedException{
Threadt1=newThread(newRunnable2());
t1.setName("t1");
//将t1这个用户线程修改为守护线程.在线程没有启动时能够修改如下参数
t1.setDaemon(true);
t1.start();
//主线程
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"----->"+i);
Thread.sleep(1000);
}
}
}
classRunnable2implementsRunnable{
@Override
publicvoidrun(){
inti=0;
while(true){
i++;
System.out.println(Thread.currentThread().getName()+"-------->"
+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
设置为守护线程后,当主线程结束后,守护线程并无把全部的数据输出完就结束了,也便是说守护线程是为用户线程服务的,当用户线程所有结束,守护线程会自动结束
Timer.schedule()
/**
*关于定时器的应用做用:每隔一段固定的时间执行一段代码
*/
publicclassTimerTest{
publicstaticvoidmain(String[]args)throwsParseException{
//1.建立定时器
Timert=newTimer();
//2.指定定时任务
t.schedule(newLogTimerTask(),newSimpleDateFormat(
"yyyy-MM-ddHH:mm:ssSSS").parse("2017-06-2914:24:00000"),
10*1000);
}
}
//指定任务
classLogTimerTaskextendsTimerTask{
@Override
publicvoidrun(){
System.out.println(newSimpleDateFormat("yyyy-MM-ddHH:mm:ssSSS")
.format(newDate()));
}
}
我是melon,一个10年编程老司机。Q我3474203856。 给melon留言或者说明是看到文章过来的。全部相关技术问题均可以一块儿寻找到答案。