首页 > 代码库 > 黑马程序员——Java多线程
黑马程序员——Java多线程
多线程基础知识
进程是一个正在执行的程序。
cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短。一个进程可能存在多条路径。迅雷的多路径。每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元。每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行。。jvm启动的时候会有一个进程就叫做java.exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中。该线程称为住线程。虚拟机至少也有两个线程,一个主线程执行,另一个负责垃圾回收的线程。下载就是多线程的。
存在的意义,能产生同时运行多段代码。
继承thread类
创建线程的第一种方式:继承thread类
线程已经被Java封装起来了,其实是windows帮你创建。
thread:允许程序并发地执行多个线程。成为thread的子类,并且重写run(runable对象。)
继承thread:
1.建立好一个对象就建立好一个线程
1.定义类执行thread
2.复写run方法。
3.调用线程的start方法,这个方法。
public class Rocket extends Thread {
private int count;
private static int num= 1;
private final int id= num++;
public Rocket( int count){ this. count= count; }
@Override
public void run (){
while (count >0 )
System . out. println( "第" +id +"号火箭发射倒计时:" +count --) ;
}
public static void main ( String[] args ) {
// TODO Auto-generated method stub
Thread t =new Rocket (10 );
Thread t2 =new Rocket (10 );
t .start ();//如果使用run()方法,将会执行完t才能执行t2;
t2 .start ();
}
/* 第1号火箭发射倒计时:7
第1号火箭发射倒计时:6
第1号火箭发射倒计时:5
第1号火箭发射倒计时:4
第1号火箭发射倒计时:3
第1号火箭发射倒计时:2
第2号火箭发射倒计时:7
第1号火箭发射倒计时:1
第2号火箭发射倒计时:6*/
} 示例中发现:创建并启动一个线程,用start()。调用线程的start方法,启动线程,调用run方法。这是因为线程启动需要调动底层资源。
发现运行结果每次都不同,因为每个线程都在获取cpu的执行权,cpu执行到谁,谁就运行。cpu在做着快速的切换已达到看上去是同时运行的结果,这就是多线程的一个特性,随机性谁抢到谁执行,至于执行多长,cpu说了算。
为什么要覆盖run方法。
thread用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法,run方法用于存储线程运行的代码,主线程放在main里面。你开启线程的意义就是为了执行你指定的代码。复写run方法的目的就让那个自定义的代码存储在run方法中,让进程运行。不能d.run,调用的run方法,主线程执行run,start没有开启线程。start开启线程,执行该线程的run方法,run就是一般调用方法,还是单线程的。
线程的运行状态。
被创建(调用windows)start开始运行,冻结(睡眠时间)时间结束回到运行wait()等待。notify唤醒功能。任务管理器的结束进程,才结束。放弃执行资格。消亡:stop和run方法结束。阻塞状态:创建了不一定就马上能执行,要等待cpu来执行,具备运行资格,但没有执行权。冻结状态也是回到阻塞状态。
获取线程对象以及名称
线程都有自己默认的名称,编号从0开始。(用super改写名称)currentthread()获取当前线程对象
getname()获取线程名称。
局部变量在每一个线程中都有自己独立的空间。
卖票程序
同时出票。
总共只有100张票,你创建了4个,卖了400张。。。用static可以,但是生命周期太长。t1start4次,会出现进程运行。跑圈,前面每跑一圈bang一枪。你已经到了运行状态,再运行没有意义。这也是不ok的,在运行的线程不需要开启。因为没有方法了,因为继承Thread类的run方法存放在类Ticket中
实现runable类。必须实现无参run方法。
实现runnable,实现run
调用:
ticket t=new t不是线程newthread才是线程饭
用多态指向ticket。在创建线程对象时就要明确运行那段代码
实现thread
thread里可以传ranable的对象,他有这样一个构造函数。实现runable接口
步骤:
1.定义类实现runable接口
2.覆盖runable里run方法
3.通过thread类创建线程对象。
4.ranable接口的子类对象作为实际参数传递给threa类的构造函数
因为自定义的run方法所属对象是runable接口的子类对象,所以要让线程去执行制定对象的run方法。就必须明确该run方法所属对象。
5.开启start并调用runnable的子类对象run;
/*Runnable run=new Rocket2(20);//虽然实现了Runnable方法,但是不能调用start
Runnable run2=new Rocket2(20);*///说明start方法是在Thread类里面的,不再Runnable中
Rocket2 r =new Rocket2 (10 ); //不能用Thread的引用指向Rocket
Rocket2 r2 =new Rocket2 (10 );
Thread t =new Thread (r );
Thread t2 =new Thread (r2 );
t .start ();
t2 .start ();
}
/* 第2号火箭发射倒计时:7
第1号火箭发射倒计时:5
第1号火箭发射倒计时:4
第1号火箭发射倒计时:3
第1号火箭发射倒计时:2
第1号火箭发射倒计时:1
第2号火箭发射倒计时:6
第2号火箭发射倒计时:5*/
另外如果对同一个启动多次会抛出异常
t .start ();
t .start ();
//throw new IllegalThreadStateException();
实现方式和继承方式的区别:
单继承。方框里的代码需要多线程去执行。学生类继承了person,有了父类,但是你要多线程执行,怎么办。我可以给你提供方法,但是你要符合我的规则。学生是人的一种,学生象runnable
实现方式的好处是避免了但继承的局限性,在定义线程时用实现的方式,而且这方式也可以共享t对象。。。。runnable。
;两种方式最大的不同就是线程代码存放位置的不同,继承存放在thread子类的run方法中,实现时,线程代码存放在接口的子类的run方法中。
安全问题
就是那个判断了,没执行的问题。多语句的时候,同时又操作了共享数据时,写多进程的时候一定要小心安全问题,否则有时测试不出来,但是中病毒了呢,问题的原因在于多条语句在在操作同一个线程的共享数据时,一个线程对多条语句只执行了一部分还没有执行完,另一条线程参与进来执行,导致共享数据的错误。
同步代码块
synchronization哪些要同步呢?操作共分享数据的语句。
同步代码块的原理:同步锁。。某段时间类只能由一条线程,直到这段代码执完毕。持有锁的线程可以在同步中执行,没有持有所得线程即使获取cpu的执行权也进不去,因为没有获取锁。火车上的卫生间
同步书写的前提,1。必须要有两个或者连着以上的线程
2.必须是多个线程 使用同一个锁,才能叫同步。必须保证同一段代码只有一个线程运行,
好处解决了多线的安全问题
弊端:多了一个判断是否上锁,消耗了资源,是在允许消耗的范围内。
同步函数。
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中那些语句是操作共享数据的。
同步封装代码和函数封装的区别:带有同步性与否。
把synchronized,作为修饰符放在函数上。两种表现形式同步代码块和同步函数。
同步函数的锁是this
怎么只有0线程在执行?因为循环锁住了。别人进不来。。。没搞清楚哪些药同步哪些不用,拿出来,调用show就好了。同步函数用得是哪一个锁呢?函数需要被对象调用。怎么验证这结论:使用两个线程来卖票,一个线程在同步代码块中,一个同步函数,都在执行卖票工作为什么都在run里执行,不执行code?哦,主函数太快了,让主函数睡一会儿。还是出现了错票0 。不安全。两个锁不一样。
练习:不要在写一个函数然后又加任何类名。
静态同步函数的是class对象。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象,Ticket.class。静态的同步方法使用的锁是所在类的字节码文件对象。类名.class。懒汉式加了锁会比较低效,因为每一个都要判断用双重否定。
懒汉式
死锁:同步中嵌套同步而锁却不同。尽量避免死锁。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。