如鹏网JAVA培训笔记33晓伟整理.docx
《如鹏网JAVA培训笔记33晓伟整理.docx》由会员分享,可在线阅读,更多相关《如鹏网JAVA培训笔记33晓伟整理.docx(16页珍藏版)》请在冰豆网上搜索。
如鹏网JAVA培训笔记33晓伟整理
写在前边的话:
2015年2月8日如鹏线上训练营第四十六天
当你在想玩什么,有人再想学什么——时间
当你在做计划,有人已经出发——执行
当你为上次失败沮丧,有人已开始下次尝试——心态
当你想放弃,有人却坚信前进就有希望!
做对事情的九个先后顺序:
1.职场:
先升值,再升职;
2.沟通:
先求同,再求异;
3.执行:
先完成,再完美;
4.学习:
先记录,再记忆;
5.投诉:
先解决心情,再解决事情;
6.人际:
先交流,再交心;
7.先成长,再成功;
8.先站住,再站高;
9.先模仿。
再创造!
学会知而不言,这样才不会言多必失;
学会自我解脱,这样才能自我超越;
学会一个人静静地思考,这样才能让自己更清醒,明白;
学会感恩,因为拥有一颗感恩的心能帮助我们在逆境中看到希望!
Java多线程:
●进程和线程的不同:
⊙通常一个进程可以包含若干个线程,它们可以利用进程所拥有的资源。
⊙进程是系统进行资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能够独立运行的基本单位。
⊙线程自己基本不拥有系统资源,只拥有一些在运行中必不可少的资源(如程序计数器,一组寄存器和栈等),线程可与同属于一个进程的其他线程共享进程所拥有的全部资源。
●多线程编程的好处:
⊙在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态。
多个线程共享堆内存(heapmemory),因此创建多个线程去执行一些任务会比创建多个进程更好。
*封装成一个方法,方法的声明需要两点:
*1.是否需要有返回值
*2.是否依赖第三方变量,即参数
只需要开启线程(start()方法),由CUP进行调度即可,自动调用run方法(抢夺CUP执行权)
多线程运行的一个特点:
随机性
java虚拟机已经帮我们创建了一个主线程,调用main方法
start()使该线程开始执行;Java虚拟机调用该线程的run方法。
(开启线程)
方式一:
继承Thread类
●自定义类继承Thread,并复写父类中的run(),将线程运行的代码放到run方法体中
●创建子类对象的同时线程也被创建
●调用线程的start方法,开启线程
方式二:
实现Runnable接口
●自定义类实现Runnable接口,并覆盖接口中的run(),将线程运行的方法放到run方法体中
●创建实现Runnable接口的子类对象,把它作为参数传递给Thread类的构造函数,创建一个Thread对象
●调用线程的start方法,开启线程
线程调度:
⊙首先创建线程对象:
newThread
⊙其次去开启一个线程:
startThread
⊙只有当线程被调度的时候才会涉及到:
线程的生命周期
1.首先调度的线程会变成可运行态(Runnable)
2.其次如果抢到了CPU的执行权,自动调用run()方法,此时此线程就进入了运行态(Running)
情况一:
如果运行态(Running)的代码体中有sleep、wait、异常等情况时,这样会导致此线程由运行态(Running)转换为阻塞态(Blockedwaiting)
情况二:
当处理了阻塞态(Blockwaiting)后,又会跳转到可运行态(Runnable)
3.如果运行态(Running)没有发生阻塞情况,顺利执行完代码块中的全部代码,则会直接进入死亡态(Dead),该线程执行结束
//this从当前类寻找getName()方法,若未找到则去父类中寻找getName方法(此时相当于super.getName)
privateStringname;
//创建构造方法
publicDemo1(Stringname)
{
this.name=name;
}
publicvoidrun()
{
for(inti=0;i<10;i++)
{
//获取线程的名称getName
System.out.println(super.getName()+"----"+i);
}
}
方法一:
//设置线程的名称
demo1.setName("Demo1");
demo2.setName("Demo2");
方法二:
//构造方法也可以为线程名进行初始化赋值
Demo1demo1=newDemo1("xiaowei");
Demo1demo2=newDemo1("nihao");
//创建线程
classDemo1extendsThread
{
//this从当前类寻找getName()方法,若未找到则去父类中寻找getName方法
//privateStringname;
//创建构造方法
publicDemo1(Stringname)
{
//构造方法也可以为线程名进行初始化赋值
//this.name=name;
super(name);//调用父类的Thread(StringThread)构造方法
}
publicvoidrun()
{
for(inti=0;i<10;i++)
{
//获取线程的名称getName
System.out.println(super.getName()+"----"+i);
}
}
}
//获取主函数的线程名称System.out.println(Thread.currentThread().getName());
currentThread()是Thread类的一个静态方法,静态方法可以直接被类名(Thread)调用,返回的是当前线程对象:
Thread.currentThread()
核心代码:
run()方法
其中sleep、stop、start等方法都是固定不变的方法,可以在Thread类中进行写死。
但是核心方法run方法是Thread类和Runable接口共性的方法,是变化的,不确定的,因此在Runnable中只有run()方法的声明,没有实现。
自定义一个类去实现Runnable接口,实质上就是去实现run()方法
在java中继承具有单一性:
一个类只能够继承一个父类,不可以继承多个父类。
实现Runnable接口解决了继承Thread类的单继承局限性
实现了Runnable接口不仅可以构建线程对象,同时还可以去继承其他的类(打破了单继承的局限性)
Thread类不能实现子线程之间共享一块资源
而实现Runnable接口方法来创建线程可以实现子线程之间共享一块资源
线程创建的两种方法:
1.Runnable这种方式:
解决了extendsThread的单继承的局限性
2.Runnable还可以进行数据资源的共享
因此,开发时,一般选择Runnable方式
线程安全性问题:
在进行判断while条件后没来得及执行输出时候,cpu的执行权被另外一个线程抢走了
//创建线程Runnable方式
classDemo5implementsRunnable
{
privateintnum=100;
publicvoidrun()
{
while(num>0)
{
//在进行判断while条件后没来得及执行输出时候,CPU的执行权被另外一个线程抢走了
System.out.println(Thread.currentThread().getName()+"正在出售"+num--);
}
}
}
线程安全问题:
导致安全问题的出现原因:
●多个线程访问出现延迟
●线程随机性
线程安全问题的解决方案:
●同步(synchronized)
多线程资源共享,可能存在安全问题,根源是:
*1.线程的随机性(人为无法控制)
*2.线程执行过程中的延迟(代码执行过程中还未执行完就被其他线程抢走了)
多线程安全问题的解决办法:
*同步(synchronized):
在线程执行多行代码体(资源共享操作)过程中
*不会释放CPU的执行权,该线程执行结束才会释放CPU执行权
同步的原理:
锁机制
每个线程在执行同步代码块的时候,首先会判断同步锁。
同步锁其实就是:
是否有线程正在执行同步代码块的一个标识。
如果这个时候已经有一个编程进来了,同步锁相当于把同步代码块锁上,阻止其他线程进入执行
优势:
解决了多线程的数据共享安全问题
缺点:
因为每次线程代码体执行都要判断同步锁,效率会降低。
同步代码块依赖于同步锁
每new一次就会产生一个新的对象,不同的对象对应不同的内存分配区间
实现同步的前提:
1.执行相同的代码块时,是否有多个线程(不是单线程)资源的共享,抢夺CPU的执行权
2.是否使用的是同一个锁
同步代码块
synchronized(锁对象)
{
需要同步的代码;
}
同步函数
publicsynchronizedvoidrun()
{
执行代码;
}
同步函数的实现方法:
//创建线程Runnable方式
classDemo5implementsRunnable
{
//定义为全局变量,只有一份
Objectobj=newObject();//创建同步代码锁(使用同一把锁)
privateintnum=100;
publicvoidrun()
{
while(true)
{
sellTicked();
}
}
//同步函数实现
publicsynchronizedvoidsellTicked()
{
try
{
Thread.sleep(100);
}catch(InterruptedExceptione)
{
e.printStackTrace();
}
if(num>0)
{
//在进行判断while条件后没来得及执行输出时候,cpu的执行权被另外一个线程抢走了
System.out.println(Thread.currentThread().getName()+"正在出售"+num--);
}
}
}
同步代码块的实现:
publicvoidrun()
{
while(true)
{
//同步代码块实现
synchronized(obj)
{
try
{
Thread.sleep(100);
}catch(InterruptedExceptione)
{
e.printStackTrace();
}
if(num>0)
{
//在进行判断while条件后没来得及执行输出时候,cpu的执行权被另外一个线程抢走了
System.out.println(Thread.currentThread().getName()+"正在出售"+num--);
}
}
}
}
同步其实是对一块代码的一个封装,函数也是对代码的一个封装
同步的另外一种表现形式:
同步函数
同步函数的体现:
(非静态同步函数)
publicsynchronizedvoidsellTicked()
{
........
}
同步函数的锁:
同步必须依赖于一个对象
●非静态同步函数:
publicsynchronizedvoidsellTicked()使用的是this锁,即当前对象
●静态同步函数
publicstaticsynchronizedvoidsellTicked()使用的是当前类的字节码(.clss)其返回的是类Class的实例对象
静态方法(static)只能访问静态数据,不可以访问非静态数据
同步代码块和同步函数的选择问题:
同步代码块:
在局部代码加同步(适用于在一个代码体中只有一部分代码要实现同步)使用锁对象是任意的(只要保证同一把锁即可)
同步函数:
对功能的进一步抽取,在方法上加同步(使用的锁对象必须是this锁或者是字节码(.clss))
同步函数更简便:
只需要在方法前加上同步关键字:
synchronized即可!