------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.