一:sleep 和wait 的区别(sleep 和监视器的区别)
相同点:可以让线程处于冻结状态
不同点:
sleep 是定义在Thread 类中的一个静态方法
wait 是定义在Object 类中的方法
- sleep 必须要指定时间////wait 可以指定时间也可以不指定时间
- sleep 时间到,线程就处于临时阻塞或者是运行状态///wait 如果是没有设置时间,必须要通过 notify 或者 notifyAll 来唤醒
- sleep 不一定要定义在同步中。sleep 是定义在 Thread 类中的一个静态方法///wait 必须要定义使用在同步中,而且要加上锁
- 定义在同步中时:执行到 sleep wait 都会释放CPU的执行权。
- sleep 不会释放锁
- wait 一定会释放锁(多条线程执行同一个函数,可以很好的解释)
二:线程如何停止
查看API中有一个stop 方法。但是已经弃用。提供的解决办法:修改某些变量以指示目标线程应该停止来达到停止线程
run 方法中通常都定义了循环,只要控制住循环就可以了。设置变量通过标识指示循环结束,线程就结束了
示例代码:
package Thread;
//演示线程停止
class SDemo implements Runnable{
private boolean flag=true;
public void run(){
while(flag){
System.out.println(Thread.currentThread().getName()+"...... ");
}
}
public void ChangeFlag(){
flag= false;
}
}
public class StopDemo {
public static void main(String[] args){
SDemo r = new SDemo();
Thread t1= new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
int x= 0;
try{Thread.sleep(100);}catch(InterruptedException e){}
while(true){
if(++x==50){
r.ChangeFlag();
break;
}
// System.out.println("main "+x);
}
System.out.println(x);
System.out.println("主线程结束!!!");
}
}
当线程处于冻结状态无法判断标记时如何让此线程停止:API中提供的方法为使用interrupt() 方法
class SDemo implements Runnable{
private boolean flag=true;
public synchronized void run(){
while(flag){
try{this.wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"...... ");
}
}
public void ChangeFlag(){
flag= false;
}
}
此时线程就冻结了。(死锁)
interrupt(): (API)
-
-
-
如果该线程阻塞的调用
wait()
,wait(long)
,或wait(long, int)
的方法Object
类,或者在join()
,join(long)
,join(long, int)
,sleep(long)
,或sleep(long, int)
,这个类的方法,那么它的中断状态将被清除,并且将收到一个InterruptedException
。
-
-
其实就是将线程的冻结状态清除。让线程继续执行(重新恢复执行资格),必须依赖其他具备执行资格和执行权的线程(因为冻结的线程不具备CPU的执行权是无法做任何执行的)
书写格式:线程对象.interrupt();
package Thread;
//冻结的线程如何停止的
class InDemo implements Runnable{
private boolean flag= true;
public synchronized void run(){
while(flag){
try{this.wait();}catch(InterruptedException e){
System.out.println(Thread.currentThread().getName()+"......."+e.toString());
ChangeFlag();
}
System.out.println(Thread.currentThread().getName()+"........");
}
}
private void ChangeFlag(){
flag=false;
}
}
public class InterruptDemo {
public static void main(String[] args){
InDemo in = new InDemo();
Thread t1= new Thread(in);
Thread t2= new Thread(in);
t1.start();
t2.start();
int x=0;
// try{Thread.sleep(100);}catch(InterruptedException e){}
while(true){
if(++x==50){
//强制唤醒t1 t2
t1.interrupt();
t2.interrupt();
break;
}
System.out.println("main..."+x);
}
System.out.println("主函数结束!!");
}
}
结合了异常,这里也是利用了异常。线程一运行就会冻结,当主线程循环执行到指定次数时就会强制性的解除现成的冻结,线程继续执行,执行解决异常的方案,就会修改标记。当线程再次执行时,标记已经都变成了 false 不会进入循环。线程停止。
三:守护线程
守护线程是后台线程,一般我们创建的线程都是前台线程
前台和后台线程运行时都是一样的,获取CPU的执行权,只是结束的时候有一些不同,
前台线程要通过run 方法结束,线程结束///////后台线程也可以通过run 方法结束,线程结束。但是还有另外一种情况——当进程中所有的前台线程都结束了,无论后台线程处于什么状态,都会结束,从而进程就会结束
进程结束依赖的是前台线程
API中提供了一种将前台线程转化为后台的方法(在线程开起之前标记为后台线程)
-
-
-
public final void setDaemon(boolean on)
将此线程标记为daemon线程或用户线程。 当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。
-
-
Java虚拟机就是一个进程,当里面的前台线程全部结束后,这个进程也会结束
Thread t1= new Thread(in);
Thread t2= new Thread(in);
t1.start();
t2.setDaemon(true);//将t2 标记为后台线程,当主线程和t1 结束后,t2 一定会结束
t2.start();
四:优先级和线程组
API中的解释
-
每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守护程序。 当在某个线程中运行的代码创建一个新的
Thread
对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时新的线程才是守护线程。当Java虚拟机启动时,通常有一个非守护进程线程(通常调用某些指定类的名为
main
的方法)。
t2.start();
System.out.println(Thread.currentThread().toString());//获得主线程的线程名称,优先级和线程组
优先级:被CPU优先处理的频率
优先级的表示:用数字表示(1-10).其中默认的初始优先级5 最明显的三个优先级1 5 10