实现Runnable接口
定义一个类实现Runnable接口
重写Runable接口中的run()方法,run()方法里是多线程要运行的代码
创建定义的那个类的对象,并将其作为参数放置于Thread类的对象里。线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就必须明确要运行的任务。
调用start()方法启动线程,执行run()方法里的内容
总结:两种方法的比较:实现Runnable接口,将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务的封装成了对象,避免了java中单继承的局限性。
多线程的安全问题
产生的原因
线程访问的延迟
线程的随机性
线程安全问题表现?原因?解决思想?解决具体的体现
当以个线程对象在执行run方法是的某一操作,其他线程进来了,并发的访问了临界资源,破坏了原子操作,造成了数据的不一致
多线程访问的延迟和线程的随机性产生了线程的安全问题
当某一线程对象进入run方法后,如果能做一个标记,说我已经在理面了,其他哥们(线程对象)你就等着吧,等我操作完了,出来了去掉标记你再进去吧,这样一来。原子操作就不会遭到破坏。
具体体现就是给那个原子操作枷锁,是整个操作同步,不让其他线程对象破坏,保证数据的一致性。
同步解决线程安全问题
同步代码块
同步代码块中的锁可以是任意对象,但是要在成员范围内定义
在局部的话,会导致锁发生变化,因为你每次执行方法,都会重新创建一个对象
同步的前提
至少要有两个线程
同一个锁
同步的好处:提高了安全性
同步的弊端:效率较低
同步函数
同步函数的使用
用synchronized关键字修饰方法即可
public synchronized void show(){
//需要的同步代码块
}
同步函数使用的锁
同步函数使用时this对象锁,静态同步函数的锁是(类名.class)
public class Singleton{
private Singleton(){}
private static Singleton s = null;
public static Singleton getInstance(){
if(s==null){
synchronized(Singleton.class){
if(s==null){
s= new Singleton();
}
}
}
return s ;
}
}
死锁
每个线程都不会释放自己拥有的锁标记,却阻塞在另外的线程所拥有的锁标记的对象池中,就会造成死锁现象。
产生原因
假如有A何B两个锁,在A锁中要使用B锁,在B锁中要使用A锁,而他们都不想让,最终导致了死锁。
因为资源不足
进程运行推进的顺序不合适
资源分配不当
产生死锁的四个条件
互斥条件:一个资源每次只能被一个进程使用
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源,在未使用之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
只要上述条件之一不满足,就不会发生死锁。
如何解决?
不同时在A锁中使用B锁,B锁中使用A锁
线程状态
CPU
CPU的执行资格:可以被CPU的处理,在处理队列中排队
CPU的执行权:正在被CPU的处理
创建:使用start()开启线程
运行:具备着执行资格,具备着执行权。
冻结:释放执行权,同时释放执行资格
从运行到冻结的方式
sleep(time),sleep(time)时间到,进入临时阻塞状态(具备着执行资格,但是不具备执行权,正在等待执行权)
wait()线程等待,notify()线程唤醒,进入临时阻塞状态
消亡
从运行到消亡的方式
stop()终止线程
run()方法结束,线程任务结束
几个方法的使用
为什么wait(),notify(),notifyAll()都定义在Object类中?
这些方法存在于同步中
使用这些方法时必须要标识所属的同步锁
锁可以是任意对象,所以任意兑现调用的方法一定定义Object类中
wait()和sleep()的区别?
对时间指定货而言
wait():可以不指定时间
sleep():必须指定时间
对执行权和锁而言
wait():释放了CPU的执行权(资格也没了),释放锁,存储于线程池。
sleep():释放CPU执行权,不释放锁(会自动醒)
停止线程
通过控制循环
interrupt()方法
stop已过时,被interrupt取代
守护线程,后台线程
你只要把一个线程设置为守护线程,那么主方法线程结束,不管什么情况,守护线程就结束。
join:加入线程,把执行权抢夺,自己执行完毕,其他线程才可能有机会执行
toString():线程名称,优先级,线程组(是有多个线程组成的,默认的线程组是main)
yield():让本线程暂停执行,把执行权给其他线程
setProproty(int num):设置线程的优先级
getPrinrity()获取线程的优先级
线程级别1-10
默认级别5
LOCK&Condition接口
Scanner类
接收从键盘输入的数据
这是java中提供的类。在util包中
基本用法:
Scanner sc = new Scanner(System.in);
int a =sc.nextInt();