1、面试题:sleep和wait的区别
相同点:
可以让线程处于冻结状态
不同点:
1、sleep必须指定时间、wait可以指定时间,也可以不指定时间。
2、sleep时间到,线程处于临时阻塞或者运行; wait如果没有指定时间,必须要通过notify或者notifyall来唤醒。
3、sleep不一定非要定义在同步中; wait必须定义在同步中
4、线程拿到锁之后,又进行sleep,线程放不放执行权?
都定义在同步中。线程执行到sleep,不会释放锁。线程执行到wait,会释放锁。
synchronized(obj){
sleep(5000);
wait(); //放不放执行权?
}
2、线程如何停止
1、stop方法过时,有其他替代方案。
线程结束,就是run方法结束。
run方法怎么结束?
run方法中通常定义循环,只要控制住循环就可以来。
注意:万一线程在任务中处于冻结状态,那么它还能去判断标记吗?不能,怎么办。
package thread;
class Demo1 implements Runnable{
private boolean flag = true;
public synchronized void run(){
while (flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"---"+e.toString());
}
System.out.println(Thread.currentThread().getName()+"----->");
}
}
//对标记的修改方法
public void change(){
flag = false;
}
}
public class Thread_interrept {
public static void main(String[] args) {
Demo1 d = new Demo1();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
int x =0;
while (true){
if(++x == 50){
d.change();
break;
}
System.out.println("main---->"+x);
}
System.out.println("over");
}
}
2、提供了一个解决方案,如果目标线程等待很长时间,则应该使用interrupt方法来中断该等待。
所谓中断线程,就是让线程从冻结状态恢复过来,让线程恢复到运行状态,重新具备cpu的运行资格。
因为是强制状态,所以会有异常发生,可以在catch中捕获异常。
在异常处理中,改变标记让循环结束,让run方法结束。
package thread;
class Demo1 implements Runnable{
private boolean flag = true;
public synchronized void run(){
while (flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"---"+e.toString());
change();//如果抛出异常,则表示t1激活,则改变标记状态
}
System.out.println(Thread.currentThread().getName()+"----->");
}
}
//对标记的修改方法
public void change(){
flag = false;
}
}
public class Thread_interrept {
public static void main(String[] args) {
Demo1 d = new Demo1();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
int x =0;
while (true){
if(++x == 50){
// d.change();
//强制对t1线程对象进行中断状态的清除
t1.interrupt();
t2.interrupt();
break;
}
System.out.println("main---->"+x);
}
System.out.println("over");
}
}
3 守护线程
也就是后台线程、一般创建的都是前台线程。
public final void setDaemon(boolean on)
//将该线程标记为守护线程,当运行的线程都是守护线程时,java虚拟机退出
线程前台后台运行都是一样的,获取CPU的执行权力。只有结束的时候有些不同。
前台线程通过run方法结束。
后台线程也可以通过run方法结束。
当前台线程都结束,后台线程无论处于什么状态都会自行结束。
比如:演员在前台表演,后台有忙碌的人员。前台如果结束,后台的忙碌也就没有意义了。
package thread;
class Demo1 implements Runnable{
private boolean flag = true;
public synchronized void run(){
while (flag){
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+"---"+e.toString());
change();//如果抛出异常,则表示t1激活,则改变标记状态
}
System.out.println(Thread.currentThread().getName()+"----->");
}
}
//对标记的修改方法
public void change(){
flag = false;
}
}
public class Thread_interrept {
public static void main(String[] args) {
Demo1 d = new Demo1();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.setDaemon(true); //将t2线程标记为守护线程
t2.start();
int x =0;
while (true){
if(++x == 50){
// d.change();
//强制对t1线程对象进行中断状态的清除
t1.interrupt();
//t2并没有进行中断
break;
}
System.out.println("main---->"+x);
}
System.out.println("over");
}
}
4 优先级
高优先级线程的执行要优于低优先级。
优先级有几级?是怎么表示的?
数字越大,优先级越高。
范围:【1-10】
其中默认的初始优先级是5。最明显的三个优先级就是1、5、10。
void setPriority(int newpriprity)
或者参数可以为Tread.MAX_PRIORITY
5 线程组
表示一个线程的集合。默认的都是main组。
四个线程,若要 进行中断,则要进行四次。
如果把线程封装到一个组里面。只要对组进行interrupt就行。
6、join和yield方法
package Thread_join;
class Demo implements Runnable{
public void run(){
for(int i = 0;i<20;i++){
System.out.println(Thread.currentThread().getName()+"...."+i);
Thread.yield(); //线程临时暂停,释放执行权,让其他线程有机会获取执行权
}
}
}
public class join_Demo {
public static void main(String[] args) {
Demo d = new Demo();
Thread t1 = new Thread(d,"t1");
Thread t2 = new Thread(d,"t2");
t1.start();
try {
t1.join(); //t1线程在这里要加入进来执行。所以想要执行就必须有执行权。主线程把执行权释放之后,处于冻结状态。什么时候恢复?等t1线程结束之后。
//用于临时加入一个运算的线程,让该线程运算完,程序才会继续运行
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
for(int i = 0;i<20;i++){
System.out.println("main------>"+i);
}
System.out.println("over");
}
}
7 开发中,线程的匿名内部类体现
package Thread_join;
public class in_class {
public static void main(String[] args) {
//用匿名内部类的方法随时创建一个线程并让其跑起来。
new Thread() {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + " x " + i);
}
}
//加大括号的意思是Thread子类对象
}.start();
Runnable r = new Runnable(){
public void run(){
for(int i = 0;i<20;i++){
System.out.println(Thread.currentThread().getName()+" y "+ i);
}
}
};
new Thread(r).start();
for(int i = 0;i<20;i++){
System.out.println(Thread.currentThread().getName()+" z "+ i);
}
}
}
面试题
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runnable run");
}
}){
public void run(){
System.out.println("sunrunnable run");
}
}.start();
到底谁会执行呢?
后面的会执行,因为子类run方法把父类的run方法覆盖了。