--什么是线程
*线程是一个程序里面不同的执行路径
*程序执行在同一时间里面,每一个执行的分支就是一个线程
*一个程序的Main()方法中的执行线路称为程序的主线程
--进程和线程
*进程是一个静态的概念,当代码被java虚拟机加载到code segment中,这个进程的生命周期就开始了
*进程是不能执行的,但是经常会说进程执行实际上是指一个进程中的主线程的执行,也就是一个程序的Main()方法中的进程开始执行
*进程是一个静态的概念,在机器上的cpu中实际上运行的都是线程,注意理清以前的这一个误区
*windows是多进程多线程的,Doc操作系统是单进程当然也就是单线程的了
*多线程最好以分支来区分好些,因为实际上在单cpu在一个时间点上只是处理单个线程,只不过时间片的东西欺骗了人的眼睛而已,但是双核就是在同一时间点上执行多个线程咯
*每一个进程都会在code segment中有一份单独的进程上下文,所以进程之间的切换会有很大的开销
*而同一个程序的多个线程共享代码区和数据空间,所以线程之间的切换开销小
*多进程:同一个时间在操作系统上运行多个任务(任务管理器)
*多线程:同一个应用程序在同一个时间执行多个分支路径
--怎样实现线程
*方法一:直接实现Runable接口,实现里面的run()方法,然后将实现类作为构造函数传入到Thread的构造函数中创建新的Thread类,调用它的start()方法,开始执行线程
*方法二:继承自Thread类,实现run()方法,然后直接调用其start()方法开始执行线程
*只有调用Thread类的start()方法开能开启一个线程,开启线程后自动调用run()方法,直接调用run()方法实际上只是方法的调用,不会开启新的线程,只有start()方法才能通知cpu开启新的线程
--线程的阻塞
*情况一CPU给你分配的时间片完了
*情况二其他情况导致阻塞,比如sleep()方法
--线程的控制
首先要知道线程的几种状态,【创建new】【就绪start】【运行run】【阻塞sleep】【死亡null】
*线程实例.isAlive()线程是不是或者,当线程实例属于【就绪】【运行】【阻塞】三者之一都是活着的
*线程实例.getPriority()--取得线程的优先级,线程实例.setPriority(long i)--设置线程的优先级
*Thread.sleep(long time)方法,让"当前"【因为是静态方法嘛】正在运行的线程睡眠,让其处于 【阻塞】状态,当睡着的时候只要被吵醒就会抛出一个InterruptedException异常,但是什么时候会被吵醒呐?
*Main()方法实际上就是主线程的run()方法,所以在main()方法中调用Thread.sleep()是让主线程睡眠【当前线程睡眠嘛】
*当调用线程实例的.interrupt()方法的时候是相当于把一个线程吵醒(妨碍的意思),如果一个线程被吵醒了,那么他会抛出InterruptedException异常,所以可以用这种方法让子线程结束奥
*但是不推荐用异常的方式来判断是否结束子线程,所以可以用线程实例.stop()方法,但是这个方法在1.5中被废弃,那怎样来解决这个问题呐?
*为什么废弃,仔细分析它比interrupt()更粗暴,人家interrupt()方法至少你还能在catch到InterruptedException异常的时候做一定得处理,但是stop()直接关闭,更加粗暴,比如被stop()的线程打开了一个文件,那你永远关不掉了
*那我们该怎么办呐?很简单嘛!当给线程类加一个bool类型的成员变量,通过线程实例来修改这个成员变量,然后做一个判断就行了撒。。呵呵,不要想的太复杂咯奥
*当当前线程睡眠后代码不会被执行,但是如果在自身睡眠之前有其他线程开启了,那其他线程会执行,当前线程睡醒之后,继续运行本线程的方法
*多个线程在同时运行时,我们是无法得知线程的运行先后次序的。但是常规上来说主线程会先开启
*线程实例.jion()方法--这个线程实例合并到当前线程中来
*当另一个线程开始运行之后,调用该方法就会将其合并回来,相当于合并到当前线程,那么只有当被合并的线程的方法执行完成之后才执行当前线程的代码
*有什么用呐?更加灵活的控制,和直接的方法调用还是有区别的,因为你可以让两个线程同时运行一段时间之后在合并开启的那个线程来完成特殊的要求嘛
*该方法也会抛出InterruptedException异常,这种情况并不是睡眠的时候被中断会抛,而是在执行的过程中如果被中断则会抛出
*线程实例.yield()方法--让出cpu,进入【就绪】状态
*线程的优先级
*范围1-10,默认为5
*常规上在启动线程之前最好设置好优先级
----------------------------------------------------------
--线程同步
*在一个普通方法调用Thread.sleep()睡眠正在调用该方法的线程,Thread.currentTread获得当前正在运行的线程实例
*第一种方法,方法的同步方法锁(默认锁定对象本身)
*第二种方法,使用同步块(可以锁定任意对象)
*两种方式的原理都是在执行该方法的时候当前对象被锁定,编译后都是一样的,只不过是编译器的一层封装而已,但是注意区别第一种只能锁定this,而第二个可以任意锁定,但是一般情况下第二种都是锁定this,当锁定this的时候两者之间是没有任何区别的
*我本身以为:【注意是”锁定“当前整个对象,而不是只是一个方法,就是说如果另一个线程调用另一个没有同步的方法,只要他要访问这个对象的任何成员都会视为非法的】XXX错误的
*但是我的结论是错误的,还是能通过其他非同步方法范围成员变量的也可以修改。。。这很特殊!
*结论:【锁定只是对一个方法起作用,虽然看似锁定对象,但是只是对方法有效,其他的方法照样能访问所谓的被“锁定的”对象的成员变量】XXX错误的
*但是这样下结论又有一定得问题,当两个同步方法都访问一个成员的时候,由于第一个方法已经锁定了this,第二个同步方法又想去锁定this,就会照成等待,等第一个方法完成之后才执行,这里又有锁定this的原理在里面
*所以啊!当成员可能被两个方法访问的时候最后这两个方法都加同步锁文档啊---这是最终结论。绝对是正确的哈
*最终结论,别的线程可以访问非同步的方法,不管当前this是否已经锁定!,但是如果访问同步方法,就需要等待其他同步的方法执行完成
*同步就是保证一个方法的原子性
--什么是死锁
*两个线程,两个对象,线程一锁住对象一,并需要锁住对象二才能完成操作,线程二锁住对象二,并需要锁定对象一才能完成操作,于是造成死锁
*解决方法
*第一种,加粗锁的粒度
-- Object对象实例.wait()方法:导致当前的线程等待(wait),直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法
-- Object对象实例.notify()方法:唤醒在此对象监视器上等待(wait)的单个线程。
--wait和sleep的区别
*wait是Object对象的成员方法,sleep是Thread的静态方法
*wait只让当前锁定该对象的线程进入等待状态,不能自动复活,只能调用它的notify方法或才能被通知复活,而sleep只让当前线程(并不要求是锁定当前对象的线程)暂时睡眠,一定时间后自动复活
*wait后线程将不再持有对象锁,但是sleep后线程继续持有对象锁
*只有在同步方法中才能使用wait(),因为他存在将对象锁放弃的动作,所以在调用方法前必须首先拥有对象锁,当notify后自动找回丢失的对象锁,而sleep方法不要求这样,sleep后有锁就继续持有,没锁也没什么关系
--其实很简单,理解下面的生产者和消费者的问题就行了
class App{
public static void main(String[] args) throws Exception{
Container c=new Container();
Prodecter pd=new Prodecter(c);
Consumer cs=new Consumer(c);
new Thread(pd).start();
new Thread(cs).start();
}
}
class Container{
int index=0;
Product[] prodects=new Product[10];
public synchronized void push(Product p){
while(index==prodects.length){
try{
this.wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
this.notifyAll();
prodects[index]=p;
index++;
}
public synchronized Product pop(){
while(index==0){
try{
this.wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
this.notifyAll();
index--;
return prodects[index];
}
}
class Product{
int id;
public Product(int id){
this.id=id;
}
}
class Prodecter implements Runnable{
private Container c=null;
public Prodecter(Container c){
this.c=c;
}
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
Product p=new Product(i);
c.push(p);
System.out.println("生产"+p.id);
}
}
}
class Consumer implements Runnable{
private Container c=null;
public Consumer(Container c){
this.c=c;
}
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
System.out.println("消费"+c.pop().id);
}
}
}