Java线程
一、 线程状态的转换
线程状态总的可分为五大状态:生、死、可运行、运行、等待/阻塞。也就是说:生是创建线程对象;可运行是调用start()方法;运行是线程调度程序选择一个线程作为当前线程是所处的状态;等待/阻塞/睡眠状态是线程有资格运行是所处的状态,换句话说,它是可运行的,如果有某事件出现,则有可能返回到可运行状态;死是线run()方法完成。
二、 阻止线程执行
1、睡眠
Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)
线程在苏醒之前不会返回到可运行状态,当苏醒之后则返回到可运行状态。
线程睡眠原因:
1、线程执行太快
2、需要强制进入下一轮
3、java规范不保证合理的轮换
睡眠的位置:将Thread.sleep()的调用放线程run()之内。
三、线程的优先级和线程让步yield()
线程的让步是通过Thread.yield()来实现的。Yield()方法的作用是:暂停当前正在执行的线程对象,回到可运行状态,从而让和他一样具有相同优先级的线程运行。它在大多数情况下能将线程从运行状态转到可运行状态,但有时候会没有效果。
线程的优先级:默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。
四、 join()方法
join()方法是让一个线程b“加入”到另一个线程a的尾部。在a执行完毕之前,b不能工作。保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。它还有带超市限制的重载版本。
Void join() //等待该程序终止
Void join(long millis) //等待该线程终止的时间最长为millis毫秒
void join(long millis,int nanos) //等待该线程终止的时间最长为millis 毫秒 + nanos 纳秒
例如:
for (int i = 0; i < 20; i++) {
System.out.println("主线程第" + i + "次执行!");
if (i > 2) try {
//t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
等同于:
for (int i = 0; i < 20; i++) {
System.out.println("主线程第" + i + "次执行!");
if(i==3){
for (int j = 0; j < 10; j++) {
System.out.println("线程1第" + j + "次执行!");
}
}
}
五、线程的同步与锁
1、同步问题提出
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。解决问题的方法:将资源共享的部分使用synchronized关键字同步方法。例如:
错误的代码:
public void run(){
try {
for(int i=0;i<5;i++){
System.out.println(t.tickets);
t.tickets--;
Thread.sleep(20);
}
} catch (Exception e) {
// TODO: handle exception
}
}
正确的代码:
public void run(){
try {
for(int i=0;i<5;i++){
synchronized(this){
System.out.println(t.tickets);
t.tickets--;
}
Thread.sleep(20);
}
} catch (Exception e) {
// TODO: handle exception
}
}
主要就是把下面的这段代码,
System.out.println(t.tickets);
t.tickets--;
使用synchronized方法
synchronized(this){
System.out.println(t.tickets);
t.tickets--;
}
其实在这里也用到了锁的原理,一个对象只有一个锁。所以,如果一个线程获得该锁,就没有其他线程可以获得锁,直到第一个线程释放(或返回)锁。这也意味着任何其他线程都不能进入该对象上的synchronized方法或代码块,直到该锁被释放。这也就避免了两个线程同时去访问共享资源从而使共享资源损坏。
在今天的作业中获得了两个小的知识点:
getState()//获取线程状态
Thread.State.TERMINATED//线程.状态.死掉
通过getState()方法获取线程的状态从而和Thread.State.TERMINATED进行对比,如:
if((th1.getState()==Thread.State.TERMINATED) && (th2.getState()==Thread.State.TERMINATED)){
System.out.println("线程运行完毕");
break;
}//如果相等的话则输出“线程运行完毕”并结束这个程序