一、多线程的实现方式
1.实现方式一:
1)写一个子线程类,继承Thread类
2)复写run方法
3)在main方法创建子类对象
4)调用start()开启线程
启动线程的方法只能是调用start()方法实现,如果是在main()方法中调用线程的run()方法那么只是当作一个普通类调用了一个普通的方法,并不会开启一个新的方法
2.Thread类的常用方法:
常用的多线程的构造方法
Thread(Runnable target)
分配新的Thread对象
Thread(Runnable target,String name)
分配新的Thread对象
//非静态方法,需要用Thread对象调用
public void setName(String name)
设置线程的名称
public String getName();
获取Thread类的名称
public void start()
启动一个线程
//静态方法,用Thread类名调用
public static Thread currentThread()//获取Thread类的对象(比较常用)
获取当前正在执行的线程对象
public static void sleep(long time)
让线程睡眠指定的毫秒值
2.实现方式二(比较常用):
1)写一个实现类 实现Runnable接口
2)复写run方法
3)创建实现类的对象
4) 创建Thread类的对象把Runable的实现类对象传递给Thread
5)调用start()方法开启线程
即:new Thread(线程执行的任务体对象(实现Runnable接口子类对象),线程名字).start();
Runnable接口中没有getName方法
不能直接getName()获取线程名
要通过Thread.currentThread().getName()获取
实现Runnable接口创建多线程的好处:
1.避免了第一种的单继承的局限性
Java中一个类只能继承一个类,类继承了Thread类就不能再继承其他类
实现了Runnable接口,还可以继承其他的类,实现其他的接口
2.增强了程序的扩展性,降低了程序的解耦性(解耦)
实现Runnable接口的方式,把设置线程任务的开启线程进行了分离(解耦)
创建了Runnable对象,调用start()方法,用来开启新的线程
3.对多个线程而言,实现了资源的共享
写一个实现类,实现Runnable接口
public class DownloadRunnable implements Runnable{
//复写run方法
//这段代码被谁执行,获取的线程名字就是谁
//run()方法是用来设置线程任务的方法
public void run(){
for(int i=0;i<=100;i++){
String name = Thread.currentThread().getName();//Thread.currentThread()获取Thread类的对象,再通过对象调用getName()获取线程对象的名字
}
}
}
二、线程安全问题
线程安全问题产生的原因:
多个线程访问【共享数据】时,当一个线程正在执行的时候还没有执行完,CPU的执行权就被其他线程抢走了,这个时候就有可能出现安全问题
线程安全问题解决方案:
1)同步代码块:
当一个线程进入同步代码块的时候,就会被锁住,其他线程就进不来;
直到同步代码块执行完,其他线程才能进来执行
锁对象:任意对象,但要保证被锁的对象唯一(否在就会锁不住)
synchronized(被锁的对象){
可能出现线程安全问题的代码
}
2)同步方法
同步方法:一个线程执行该方法,方法中的代码就全部锁住
public synchronized void 方法名(){
可能出现线程安全问题的代码
}
类名.class(字节码文件/对象(类的字节码也是可以作为被锁的对象而且更好因为字节码对象只会有一个,符合锁对象要求,只不过是Class类型))
三、线程状态
NEW(新建状态):至今尚未启动的线程处于这种状态。
RUNNABLE(运行状态):正在 Java 虚拟机中执行的线程处于这种状态。
BLOCKED(阻塞状态):在等待CPU的执行权
WAITING(无限等待):无限等待,没有叫醒你就一直等
TIMED_WAITING(计时等待):在有限的时间内等待,时间到了就自动醒来
TERMINATED(死亡状态):线程执行完毕
1.当线程较少时,其他线程执行notify()方法,唤醒处于无限等待的线程,此时线程就获得锁对象直接进入可运行状态,如果线程较多(一般有2~3个以上)就进入被阻塞状态参与对cpu的竞争中;
2.处于计时等待的线程同上
线程计时⏲与唤醒的方式
进入到TimeWaiting(计时等待有两种方式)
1、使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Block状态
2、使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入到Runnable/Block状态
唤醒的方法:
void notify()唤醒在此对象监视器上的等待的单个线程
void notifyAll()唤醒在此对象监视器上的等待的所有线程
正在运行的程序就是进程
一个方法就是一个线程,而一个进程中不止包含一个方法,但一个方法就是执行进程的基本单元
主线程(main线程)和其他线程都是同优先级的所以CPU是随机执行的
Thread.sleep()方法是让程序执行速度放慢,放大程序出错的机率,不是程序出错的原因
静态方法访问的方法或成员变量都必须是静态的