java多线程(二)

来源:互联网 发布:值乎不见了 编辑:程序博客网 时间:2024/05/18 00:32

博主qq656358805,欢迎交流!


上回书说到线程的同步以及安全问题,下面紧接上次内容我们开始谈谈线程的死锁以及调度。


这里顺便说一下类的加载,类只有在被使用的时候才会加载其内部所有的属性和方法,换句话说一个赋值语句所涉及到的属性所在的类只有被加载的时候才会使这个属性有价值,那么我们联想到内部类,当我们把一个赋值语句放入一个类的内部类的时候,只要不调用涉及该类的方法便可以延缓属性的加载时间。

 

死锁:过多的同步容易造成死锁,无同步不死锁,死锁一定是两者或多者共用同一资源。

package 死锁演示;  

 

public class Syn

{

public static void main(String[]args)

{

Object a=new Object();  //这里定义两个公共资源ab

Object b=new Object();

Situationone s1=new Situationone(a,b); //将资源分别给两者使用

Situationtwo s2=new Situationtwo(a,b);

Thread one=new Thread(s1);

Thread two=new Thread(s2);

one.start();

two.start();

}

 

}

 

class Situationone implements Runnable{

 

Object a;

Object b;

public Situationone(Objecta,Object b)

{

this.a=a;

this.b=b;

}

public void run()

{

while(true)

{

go();

}

}

public void go() //此方法之前资源ab都存在,此方法先锁住了资源a,只剩资源b

{

synchronized(a){

try{

Thread.sleep(500);//休眠的目的是扩大死锁发生的几率,因为在休眠时间时间片转换到另一个situation类的go方法,然后锁住资源b,现在则公共资源全部被占用,导致了锁住资源a的线程进入不了锁b的代码块,也就卡在了当前代码块中,另一个线程同理。

}catch(InterruptedExceptione)

{

e.printStackTrace();

}

synchronized(b){

}

}

System.out.println("没有被死锁");

}

}

class Situationtwo implements Runnable{

 

Object a;

Object b;

public Situationtwo(Objecta,Object b)

{

this.a=a;

this.b=b;

}

public void run()

{

while(true)

{

go();

}

}

public void go()

{

synchronized(b){

try{

Thread.sleep(500);

}catch(InterruptedExceptione)

{

e.printStackTrace();

}

synchronized(a){

}

}

System.out.println("没有被死锁");

}

}

这个程序说明了造成死锁的原因是,各类方法的强制性,他们必须要求满足一定的条件才可以继续自己的执行,然而谁知道资源仅有一份。

 

下面是死锁解决的方案:

生产者消费者模式:先生产再消费。

生产完毕通知消费,消费完毕通知生产。

wait()会释放资源,sleep()不释放资源。(没有同步就没有wait)

 

If(Flag)判断等待的对象。

生产者等待,开始消费,则生产者wait,消费者消费,消费后,调用notify()唤醒生产。

消费者等待,开始生产,则消费者wait,生产者消费,生产后,调用notify()唤醒生产。

注意如果多个线程生产或消费需要同时唤醒所有,则调用notifyall()。

 

那么可以联想一下,生产者和消费者模式如同十字路口装上了红绿灯。

 

 

--线程任务调度:

package 调度演示;

 

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

 

public class Syn

{

public static void main(String[]args)

{

Timer t=new Timer(); //计时器用来安排线程的执行时刻以及频率

t.schedule(new TimerTask() {

@Override

public void run() {

System.out.println("调度");

}

}, new Date(System.currentTimeMillis()+1500),500);

}

}

//schedule()的第一个参数为被调度的线程,它是一个timertask类继承了Runnable类,第二个参数为被调度的线程在多长时间后执行,第三个参数是每隔多少毫秒执行一次,线程的调度可用来细化某些程序中的时间点从而提高效率或者完善效果。

 


0 0