您的位置:首页 > 职场人生

黑马程序员----十三-多线程

2016-01-26 11:44 573 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
==========================================

13-01-08

==========================================

1.线程的状态

run方法结束,线程的任务结束了,也可以调用stop()方法来强制结束.

2.冻结

这个线程不在运行,但是还存活.调用sleep(time)方法.必须指定时间.时间到了就自动醒了.

也可以用wait()方法,再调用notify()唤醒.

3.运行状态的线程有cpu的执行资格,还有cpu的执行权.

  冻结状态的线程释放执行权和执行资格.

  临时阻塞状态就是具备执行资格,但是正在等待执行权.

  冻结状态的醒来后有可能是运行状态也可能是临时阻塞状态.

==========================================

13-01-09

==========================================

回顾:先1.run(),再2.start(),肯定是先执行完1,才会执行2.

     创建线程的第一种方式:继承Thread类

1.继承Thread类后,如果类中是别的方法,不用改名字也可以,直接把方法放到run()方法里面就行了.

2.如果子类要继承Thread类怎么办?

  如果让父类继承Thread,那么整个体系都变成了线程体系.

  解决:如果要把一部分代码变成线程任务,但是现在又有父类,那么就要扩展Demo的功能.但是现在有了父类了,那么就只能实现接口.

  准备扩展Demo类的功能,让其中的内容可以作为线程的任务执行.通过接口的形式完成.

3.实现的话,有没有提供接口呢?打开API查,在java.lang中,有Thread,中有run()方法,中有接口Runnable,Runnable其实本身就是java.lang包中的一个接口.

  Runnable接口应该由那些打算通过某一线程执行其实例的类来实现.类必须定义一个run()方法.

4.Demo implements Runnable,只要把想在线程运行的代码放到run()方法里面就可以了.

  但是Demo还不是Thread线程对象,所以不能开启start(),如何开启?

  Demo d=new Demo();

  Thread t1=new Thread(t);

  t1.start();

  这就是创建线程的第二种方式:实现接口

  1.定义类实现Runnable接口

  2.覆盖接口中的run方法,将线程的任务代码封装到run方法中.

  3.通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递

  为什么?

  因为线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就必须明确要运行的任务.

  4.调用线程对象的start方法开启线程.

==========================================

13-01-10

==========================================

1.疑问:两个run方法,怎么运行的?

  原理:

  一个Thread(){}

  还有Thread(Runnable r){  this.r=r;  }

  提供了两个

  一public void run{  r.run();  }

  二public void start{  run();  }

==========================================

13-01-11

==========================================

1.实现Runnable的好处,不用继承所有功能.它的出现仅仅是将线程的任务进行了对象的封装.

2.Runnable r=new Student();

  Thread t=new Thread(r);

  t.start();

3.实现Runnable接口的好处

  1将线程的任务从线程的子类中分离出来,进行了单独的封装.

     按照面向对象的思想将任务封装成对象.

  2避免了java单继承的局限性.

    

  所以,创建线程的第二种方式较为常用

==========================================

13-01-12

==========================================

1.需求:卖票

  用4个窗口卖票.互相不干扰,所以用多线程.

2.因为几个线程共用一个数据,所以num可以设置成静态.

 

3.为什么有些数字会在1后面,因为已经计算过了,但是没有打印出来,1先打印出来了.

4.如果不用静态,有什么办法

  就不要继承Thread了,就实现Runnable接口,

  Ticket t=new Ticket();

  Thread t1 t2 t3 =new Thread(t1 t2 t3);

  t1.start();

  t2.start();

  t3.start();

5.如果是两个窗口卖100,另两个窗口卖100,

  Ticket t=new Ticket();

  ticket tt=new ticket();

  th t1=new th(t);

  th t2=new th(t);

  th t3=new th(tt);

  th t4=new th(tt);

==========================================

13-01-13

==========================================

1.假设现在num=1,四个线程都已经进来了,线程0满足num>0,进来了,现在cpu切换了,处理线程1了,然后线程1也进来了,输出的时候就会出现票剩下-1的情况.还可能出现-1,-2,-3.

  这样就出现了安全问题.

2.要调试出这种情况,就在输出语句之前使用sleep方法来暂停一下,sleep(long millis),加入一个Thread.sleep(10)也就是10毫秒,sleep方法里有一个异常声明,InterruptedException,是中断异常,所以catch这个异常,因为是一个中断异常,所以只能用catch,所以

try{Thread.sleep(10);}

catch{InException e)}{}

==========================================

13-01-14

==========================================

1.安全问题产生的原因.

  1多个线程在操作共享的数据

  2操作共享数据的线程代码有多条

2.当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生.

==========================================

13-01-15

==========================================

1.把if(num>0)和输出语句封装成一个整体.

 

2.解决思路:

  将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算.

3.通常封装是用{}大括号,再加个标识,synchronized.

4.在java中,用同步代码块就可以解决这个问题,同步代码块的格式是

synchronized(对象)

{

需要被同步的代码;

}

对象代表什么,相当于一个标记,Obj一个obj,放在括号里,如果有线程3,说明0,1,2都已经建立了.

==========================================

13-01-16

==========================================

1.4个线程进来了,线程0如果进来了,线程1就进不来,就算碰到了sleep,cpu切换到了其他线程,其他线程还是进不来,线程0执行完之后,线程1才进来.所以obj就相当于一个锁一样,控制线程进出.就叫同步锁.

2.同步的好处:解决了线程的安全问题.

  同步的弊端:相对降低了效率.因为同步外的线程都会判断同步锁.

3.同步加完之后安全问题依然存在,怎么办

  同步的前提:

  必须有多个线程并使用同一个锁.

==========================================

13-01-18

==========================================

1.别都放在同步代码块里面,会出问题的.

2.如果让函数具备同步性,就同时解决了封装和同步的问题.

  所以把同步关键字synchronized作为函数修饰符就可以了.

  public synchronized void add(int num)

  这就称之为同步函数.

  这是同步的第二种表现形式,第一种是同步代码块.

3.同步代码块有同步锁,但是同步函数的锁是什么呢?

4.一个在同步函数里,一个在同步代码块里,如果两个用的是一个同步锁,那么就是同步的,如果用的不是一个同步锁,那就不是同步的.

5.定义一个布尔 boolean flag=true;

t1.start();

t.flag=false;

t2.start();

这样两个线程就分开了

6.主线程开启了0线程之前,可以把主线程停一下,在t.flag之前插入

try{Thread.sleep(10);}

catch{InterruptedException e}{}

7.同步函数使用的锁是this.

  同步函数和同步代码块的区别:

  1同步函数的锁是固定的this(当前的对象),同步代码块的锁是任意的对象.开发的时候用同步代码块比较多.

==========================================

13-01-19

==========================================

1.睡眠的格式

try{

Thread.sleep(10);

}

catch(InterruptedException e)

{}

放在synchronized上面比较好,这样就可以休息10毫秒然后cpu切到其他线程的概率就非常大.

2.把函数给同步了,那么进了这个函数,其他线程就进不来.其他线程是可以得到执行权的,但是进不来.

3.验证同步函数的锁是哪一个.

0线程和1线程都有,但是都是在函数中执行的,t1.start();t.flag=false;t2.start();三句话,cpu在有执行权的时候,一下子就全部执行了,所以开启两个start的时候,flag就已经是false了,所以会发现连0线程的也都是在同步函数show里面执行的.

  那么就在t.flag=false;之前让主线程睡眠一下,t1的start就会用true来执行了.

  执行结果是0线程全是obj,1线程全是function,如果他们是同步的,就不会出现安全问题,如果没同步,就会出现安全问题.结果是有安全问题的,说明他们是不同步的.

  所以同步函数和同步代码块用的锁是不一样的.同步函数用的锁是this.

==========================================

13-01-20

==========================================

1.同步函数可以使用static静态

  静态同步方法当中根本没有this.这个函数进内存的时候只有一个当前的字节码文件对象.

  this.getClass()

2.Class c1=t.getClass();

  Class c2=Ticket.class;

  两种都行.

3.静态的同步函数使用的锁就是该函数所属的字节码文件对象,这个对象可以用getClass或者当前类名.class获取.只要保证多个线程使用的是同一个同步锁(对象)就行.

==========================================

13-01-21

==========================================

1.多线程下的单例

  饿汉

  private static final Single s=new Si();

  private Single(){}

  public static Single getInstance()

 {  return s;  }

  懒汉

  private static Single s=null;

  private Single(){}

  public static Single getInstance()

  {

 if(s==null)

 s=new Single();

 return s;

   }

2.懒汉式是否有安全隐患

  线程0和线程1都通过判断s==null,所以创建了两个对象,所以有安全问题.所以加同步

  public static synchronized Single getInstance()

3.每次拿对象都要判断锁,所以效率低,getClass方法不是静态的,所以不能用.

4.每次都要判断锁,怎么提高效率,改成同步代码块,然后前面加if(s==null),以后s就不是null了,就不用再判断锁了.

加同步是为了解决安全问题,加判断是提高效率.

5.还是写饿汉简单.面试的时候都面懒汉式.

==========================================

13-01-22

==========================================

1.死锁的情况.

  常见情景只一:同步的嵌套.

 

2.用两个锁试一试

  在同步函数中加入同步代码块,同步代码块的锁用obj,同步代码块中用同步函数,同步函数的锁是this.

3.有可能中断,有可能马上中断,有可能交叉.

 

4.面试多线程的时候有可能要写一个死锁程序.

==========================================

13-01-疑问

==========================================

1.Object obj=new Object();放在run方法里面和放在run方法外面为什么区别这么大.

2.堆里面多了一个Ticket,两个变量,一个num,一个obj,4个线程.

3.Person p=new Person();

p.show();

p.show();

被两个线程执行,两个线程栈里面都有show方法,是同一个对象.地址是同一个.

4.如果run方法里,int x=10;那么每个线程栈里都有x=10;4个线程在同时执行,判断obj,0在用,1不能用.如果new了Object(),那么每个线程都有自己的obj.

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: