多线程
第一章 线程的创建
第一节 两种创建方法
1继承Thread类,并复写run方法
2实现Runnable接口,并复写run方法
3两种方式的特点和优缺点,以及应用。卖票程序中,使用1方法创建的线程,每创建一个线程,都有100张票。而我们想要的多个线程共同操作这100张票,这时就要使用第二种方法。
第二节 线程的运行状态
1被创建 start()——>运行
2运行
3冻结 使用sleep(毫秒值) ,wait()方法放弃执行资格。
唤醒线程notify() ,notify()是继承自object类中的方法。线程被唤醒后,进入了阻塞状态
4阻塞状态 一种临时状态,具备执行资格,但没有执行权
5消亡 使用stop()方法;run方法运行完毕。
第三节 获取线程对象以及名称
每个线程都有自己默认的名称。在创建线程时,可以通过String类型的参数传入的方式或是使用setName()方法给线程自定义名称。得到线程对象后,可以通过getName()获取当前线程的名称。
获取线程对象。通过静态的currentThread()方法可以获取当前线程对象。
第二章 线程的安全问题
classTicket implements Runnnable{
private int ticket 100 ;
public void run(){
while(true){
if(ticket>0){
System.out.println(“票号”+ticket--);//先把ticket输出,再自减。
}
}
}
}
加入有4个线程,0线程判断ticket>0后还未执行打印自减的语句,cpu就将程序切换1,2,3到线程,这些线程判断ticket>0,没有执行打印自减的语句。线程切换回0线程,打印自减,然后切换到1线程时,就不再判断ticket是否大于0了,所以当ticket小于线程数的时候,就会出现不存在的票的情况。这种意外情况,称之为安全问题。
安全问题产生的原因是多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
对于有多个线程,run方法中有多条语句操作共享数据的情况,在一个线程执行语句期间,其他线程不可以参与执行,即让一个线程执行完毕以后,其他线程才可以进入run方法。
对于本节所讲的售票程序,当线程0在运行时,线程1、2、3即使拿到了执行权限,也不可以运行,就可以规避错误。
第一节 同步代码块
java对多线程的安全问题提供了专业的解决方式,就是同步代码块synchronized(对象){需要被同步的代码}。其中对象可以是任意的实例化对象。这个对象称为锁旗标,或监视器。只有持有锁的线程可以在同步代码块中执行。线程离开同步代码块时将锁释放。
第二节 同步函数
同步代码块用来封装代码,函数也是用来封装代码。可以将同步的关键字synchronized用于修饰函数,例如public synchronized void(){}
第三节 锁
同步函数的锁匙this。静态同步函数的锁是Class对象。即.class文件
同步函数的锁是this的验证
class Ticket implements Runnable
{
int ticket = 100 ;
Object obj = new Object();
boolean flag = true ;
public void run()
{
if(flag)
{
while(true)
{
synchronized(obj)
{
if(ticket> 0)
{
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()+" -------"+ticket --);
}
//show();
}
}
}
else
while(true)
show();
}
public synchronized void show()
{
if(ticket > 0)
{
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()+" "+ticket --);
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket tic = new Ticket();
Thread thr1 = newThread(tic,"one");
Thread thr2 = newThread(tic,"two");
thr1.start();
try{Thread.sleep(10);}catch(Exceptione){};
tic.flag = false;
thr2.start();
}
}
第四节 死锁
同步中嵌套同步,而持有的锁不同
单例设计模式
饿汗式
classSingle{
private static final Single s = new Single() ;
private Single(){
}
publicstatic getInstance(){
return s ;
}
}
懒汉式
class Single{
pirvate static Single s = null ;
private Single(){}
public static Single getInstance{
if(s == null){
synchronized(Single.class){
if(s == null ){
s= new Single();
}
}
}
return s ;
}
}
线程间通信
第一节 线程间通信
其实就是多个线程在操作同一个资源,但是操作的动作不同。
定义r.notify() ; r.wait();
第二节 解决安全问题
第三节 等待唤醒机制
第四节 代码优化
线程的其他操作
第一节 停止线程
interrupt(),此方法会抛出异常。
第二节 守护线程
main线程是前台线程,可以使用setDaemon(boolean on)方法,将一个线程标记为后台线程,当前台线程结束,被标记为后台线程的线程也随之结束。setDaemon(boolean on)方法要在线程开始前调用。
第四节 join方法
A线程运行时,执行到了B线程调用join方法的语句,会释放执行权,处于冻结状态,
直至B线程运行结束,A才会运行。join方法,可以用来临时加入线程执行。
方法得到执行权的线程运行完毕,。
第五节 优先级&yield方法
优先级代表抢执行权的频率,所有线程包括主线程默认优先级是5。优先级可以从1~10。
static int MAX_PRIORITY
线程可以具有的最高优先级。
static int MIN_PRIORITY
线程可以具有的最低优先级。
static int NORM_PRIORITY
分配给线程的默认优先级。
更改线程的优先级。void setPriority(intnewPriority)
static void yield()暂停当前正在执行的线程对象,并执行其他线程。稍微减缓线程运行的频率