1:多线程
(1)就是应用程序有多条执行路径。
进程:就是正在运行的程序。
线程:就是进程的执行路径,执行单元。
(2)如何使用多线程程序:
A:方式1 继承Thread类。
a:创建类继承Thread类
b:重写Thread类的run()方法。
run()方法里面才是封装线程的代码。
c:通过调用start()方法启动线程并调用run()方法。
代码体现:
public class MyThread extends Thread
{
public void run()
{
for(int x=0; x<100; x++)
{
System.out.println(getName()+"---"+"hello"+x);
}
}
}
public MyThreadTest
{
public static void main(String[] args)
{
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
my1.start();
my2.start();
}
}
ps:利用扩展Thread类创建的多个线程,虽然执行的是相同的代码,但彼此相互独立,且各自拥有自己的资源,互不干扰
B:方式2 实现Runnable接口
a:创建一个类实现Runnable接口
b:重写run()方法
c:创建实现类对象,并把它作为参数传递给Thread类的构造方法,创建Thread对象
d:通过Thread的对象执行
代码体现:
public class MyRunnable implements Runnable
{
public void run()
{
public void run()
{
for(int x=0; x<100; x++)
{
System.out.println(Thread.currentThread().getName()+"---"+"hello"+x);
}
}
}
}
public class MyRunnableTest
{
public static void main(String[] args)
{
MyRunnable my = new MyRunnable();
Thread t1 = new Thread(my);
Thread t2 = new Thread(my);
t1.start();
t2.start();
}
}
ps:这种方式不仅有利于程序的健壮性,避免了单继承的局限性。使代码能够被多个线程共享,而且代码和数据资源相对独立,从而特别适合多个具有相同代码的线程去处理同一资源的情况
C:开发过程中常遇到匿名内部类:本质上是一个继承了父类或者实现了接口的匿名的对象。
new Thread(new Runnable() {
@Override
public void run() {
//do sth .
}
}).start();
它在线程并发不多的程序中确实不错,而假如这个程序有很多地方需要开启大量线程来处理任务,
那么如果还是用上述的方式去创建线程处理的话,那么将导致系统的性能表现的非常糟糕,
更别说在内存有限的移动设备上,主要的影响如下:
1、性能上的缺失:线程的创建和销毁都需要时间,当有大量的线程创建和销毁时,那么这些时间的消耗则比较明显,将导致性能上的缺失
2、线程缺乏统一管理:大量的线程创建、执行和销毁是非常耗cpu和内存的,这样将直接影响系统的吞吐量,导致性能急剧下降,
如果内存资源占用的比较多,还很可能造成OOM
3、内存抖动:大量的线程的创建和销毁很容易导致GC频繁的执行,从而发生内存抖动现象,而发生了内存抖动,
对于移动端来说,最大的影响就是造成界面卡顿
而针对上述所描述的问题,解决的办法归根到底就是:重用已有的线程,从而减少线程的创建,也就是线程池。
(3)线程的随机性原理
多个程序其实是CPU的在做着高效切换执行的。
(4)线程的生命周期
新建
就绪
运行
阻塞
死亡
(5)线程安全问题:线程的随机性和延迟性
A:卖票案例
B:为什么有问题
a:有共享数据
b:共享数据被多条语句操作
c:在多线程环境中
(6)线程安全问题的解决方案:
A:同步代码块
synchronized(锁对象:多个线程必须使用同一个锁对象)
{
被同步的代码
}
B:同步方法
把synchronized加在方法上。
一般推荐使用同步代码块。
线程死锁:
public class DieLock extends Thread{
public boolean flag;
public DieLock(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
synchronized (MyLock.objA) {
System.out.println("true----a");
synchronized (MyLock.objB) {
System.out.println("true----b");
}
}
}else {
synchronized (MyLock.objB) {
System.out.println("false----b");
synchronized (MyLock.objA) {
System.out.println("false----a");
}
}
}
}
}
(7)线程间的通信问题
学生类:
设置学生属性的类:
获取学生属性的类:
测试类:
(8)常见的方法
优先级
暂停线程
加入线程
守护线程
(9)面试题:
sleep()和wait()的区别?
sleep是Thread()的静态方法,需要传递参数,不释放锁对象。
wait():是Object的方法,可以不用传递参数,释放锁对象。
启动线程到底调用的是哪个方法?
通过调用Thread类的start()方法来启动一个线程,
这时此线程是处于就绪状态,
并没有运行。
然后通过此Thread类调用方法run()来完成其运行操作的,
这里方法run()称为线程体,
它包含了要执行的这个线程的内容,
Run方法运行结束,
此线程终止,
而CPU再运行其它线程,
而如果直接用Run方法,
这只是调用一个方法而已