线程
一个java程序至少有两个线程,一个是默认的执行main的主线程,一个是垃圾回收器的线程。线程不会提高效率会提高资源的利用率
多进程弊端:增加cpu负担,降低进程中线程的执行概率,引发进程安全问题,出现死锁现象
Jvm创建的主线程就是把main中的代码添加到了线程的任务代码中,自定义的线程的任务代码就写在run中
多线程一般都用于循环,要不直接调用方法就可以了。
创建多线程的方式有两种:1、一种是将类声明为thread的子类,该子类重写run方法,创建类对象调用start方法开启线程。2、声明实现Runnable接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。实际上是thread中的run调用了runnable实现类中的run方法。推荐第二种,
class PrimeRun implements Runnable {
public void run() {
system.out.print(this);
system.out.print(thread.currentthread());
}
}
PrimeRun p = new PrimeRun();
new Thread(p).start();
千万不能直接调用run方法,相当于在主线程中执行run,并不会开辟新线程执行。调用sleep线程进入阻塞状态,时间一到进入就绪态,调用wait进入阻塞状态,需要用notify或者notifyall唤醒进入就绪态(没有等待的也没事)。Wait与notify是属于object类的方法,必须在同步代码块或者同步方法中才能使用这两个方法,必须由锁对象调用否则执行会报错
一个线程执行了wait方法,该线程就会进入一个以锁对象为标识符的线程池中等待并且释放锁对象,执行了notify方法,就会唤醒以锁对象为标识符的线程池等待的其中一个线程(一般先等待的被唤醒,但并不保准)。
停止线程可以用stop方法(已过时),一般都是在线程中设置标志位,手动设置退出循环让线程执行完毕,如果有wait还要先notify。调用interrupt方法也可以唤醒,但是被唤醒的线程会收到一个interruptException(wait和sleep方法已经声明会抛出interruptException异常了)
线程常用方法:thread(string)初始化线程名字(有默认的名字thread-数字),getname返回线程名字,setname,sleep,getpriority返回优先级,默认是5(继承thread的优先级,main线程也是5),setpriority(int),currentthread(静态方法)返回执行该方法的线程对象。
Sleep是哪个线程调用哪个线程睡眠(sleep是静态方法,直接用类名调用好)
testhread test = new testhread();
test.sleep(1000);
test.start();虽然调用的testthread对象的sleep,但是是在主线程中执行的,所以睡眠的是主线程
重写的run方法不能抛出异常,也就是说在run调用抛出编译异常的方法只能用trycatch块,不能用throws声明run方法。因为thread的run方法没有抛出异常,所以子类重写不能抛。
优先级范围1——10,优先级高只是执行概率高
出现线程安全问题的原因:多线程操作同一个共享的资源,多条代码操作资源
线程安全解决方案:sun提供了线程同步机制
方式一:同步代码块。
Synchronized(锁对象){需要被同步的代码}任何对象都可以作为锁状态,因为任何对象内部都维护了一个状态,java同步机制就是使用了对象中的状态作为了锁的标识。多线程的锁对象必须是唯一共享的,否则无效
方式二:同步方法
Synchronized修饰方法,静态方法的锁对象为该方法所在的类的字节码文件(当使用到某个类,加载类文件之后会自动生成一个Class类的对象存放该字节码文件的信息),非静态方法为调用该方法的this对象。同步方法的锁对象是固定的,不能修改
推荐使用同步代码块。
同步机制解决了线程安全问题,同时引发了死锁问题
死锁问题原因:存在多线程,存在多个共享资源。
死锁问题没有解决方案,只能设计程序时尽量去避免
守护线程(后台线程):在一个进程中,如果只剩下了守护线程,那么守护线程也会死亡。主线程结束,守护线程也应该结束。通过调用thread子类的isdaemon判断是否是守护线程(线程默认都不是守护线程),setdaemon(boolean)可以设置为守护线程,必须在start之前调用。
哪个线程调用join方法,就把join对象的线程加入进来,让该线程先执行完毕,注意:要先调用start才能join
阅读(2099) | 评论(0) | 转发(0) |