上一篇文章是初步了解多线程,以及多线程的java实现,现在我们围绕线程状态的关系图,分析线程状态间的调度。
isalive()判断线程是否启动
package thread;
/**
*
* 判断线程是否启动
* @author shangwei
*
*/
public class isalive implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String[] args){
isalive is = new isalive();
Thread demo = new Thread(is);
System.out.println("线程启动之前---"+demo.isAlive());
demo.start();
System.out.println("线程启动之后---"+demo.isAlive());
}
}
在java中每次程序运行都会至少启动2个线程,一个是main线程,一个垃圾回收线程,每当使用java命令执行一个类的时候都会启动jvm,每一个jvm在操作系统中会生成一个进程。
我们看一下运行结果,分别出现了2种结果:
第一种:
线程启动之前---false
Thread-1
Thread-1
Thread-1
线程启动之后---false
第二种:线程启动之前---false
线程启动之后---true
Thread-1
Thread-1
Thread-1
我们可以看出主线程可能在子线程结束之前结束,并且子线程不受影响,不会因为主线程的结束而结束。
join() 线程强制执行
package thread;
/**
* join 指定的线程加入到当前线程
* @author shangwei
*
*/
public class joinTest implements Runnable{
public static int a = 0;
@Override
public void run() {
for(int k =0;k<5;k++)
{
a = a+1;
}
// TODO Auto-generated method stub
}
public static void main(String[] args) throws Exception{
Runnable r = new joinTest();
Thread t = new Thread(r);
t.start();
t.join();
System.out.println(a);
}
}
请问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。当然这也和机器有严重的关系。为什么呢?我的解释是 当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0 。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。
源代码
/**
* Waits at most <code>millis</code> milliseconds for this thread to
* die. A timeout of <code>0</code> means to wait forever.
*/
//此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁
sleep()线程的休眠
package thread;
public class sleep implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<3;i++){
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+i);
}
}
public static void main(String[] args){
sleep s = new sleep();
Thread demo = new Thread(s,"线程");
demo.start();
}
}
线程0
线程1
线程2
interrupt()线程中断
interrupt 不会中断一个正在运行的线程,它的作用是在线程遇到阻塞的时候抛出一个中断信号,这样线程就得以退出阻塞的状态。如果线程被wait,join,sleep三种方法之一阻塞,那么它将收到一个中断一场,从而尽早的终结被阻塞的状态。
package thread;
public class interrupt implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("执行run方法");
try {
Thread.sleep(10000);
System.out.println("线程休眠完成");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("休眠被打断");
e.printStackTrace();
}
System.out.println("线程正常终止");
}
public static void main(String[] args){
interrupt in = new interrupt();
Thread t = new Thread(in,"线程");
t.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();//2s后中断线程
}
}
运行结果:
执行run方法
休眠被打断
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at thread.interrupt.run(interrupt.java:10)
at java.lang.Thread.run(Thread.java:695)
线程正常终止
优先级
java优先级是一个整数,其取值范围是1(Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY)。
thread源代码里对NORM_PRIORITY(数值为5)的注释是‘线程的默认的优先级’
public final static int NORM_PRIORITY = 5;
其实不然,默认的优先级是父线程的优先级,在init方法里,
- Thread parent = currentThread();
- this.priority = parent.getPriority();
这里理解是因为java线程的主线程(main方法)的优先级默认是为NORM_PRIORITY,这样不主动设定优先级后,后续创建的线程的优先级也都是NORM_PRIORITY
- public static void main(String[] args) {
- System.out.println(Thread.currentThread().getPriority());
- }
执行结果是5
package thread;
public class priority implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"运行"+i);
}
}
public static void main(String[] args){
priority p = new priority();
Thread t1 = new Thread(p,"A");
Thread t2 = new Thread(p,"B");
Thread t3 = new Thread(p,"C");
t1.setPriority(8);
t2.setPriority(2);
t3.setPriority(6);
t1.start();
t2.start();
t3.start();
}
}
执行结果:
A运行0
A运行1
A运行2
A运行3
A运行4
A运行5
A运行6
A运行7
A运行8
B运行0
C运行0
A运行9
B运行1
C运行1
C运行2
C运行3
C运行4
C运行5
C运行6
C运行7
C运行8
C运行9
B运行2
B运行3
B运行4
B运行5
B运行6
B运行7
B运行8
B运行9
yield() 线程的礼让
package thread;
public class yield implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<5;++i){
System.out.println(Thread.currentThread().getName()+"运行"+i);
if(i ==3){
System.out.println("线程礼让");
Thread.currentThread().yield();
}
}
}
public static void main(String[] args){
yield y = new yield();
Thread t1= new Thread(y,"线程A");
Thread t2= new Thread(y,"线程B");
t1.start();
t2.start();
}
}
运行结果:
线程A运行0
线程A运行1
线程A运行2
线程A运行3
线程礼让
线程B运行0
线程B运行1
线程B运行2
线程B运行3
线程礼让
线程A运行4
线程B运行4
同步锁
还记得上一篇文章中的共享资源的案例吗?我们稍微改动下,加一个休眠时间
package thread;
public class runnable_share_4 implements Runnable {
private int count = 5;
public static void main(String[] args){
runnable_share_4 h1 = new runnable_share_4();
Thread t1 = new Thread(h1,"1号窗口");
t1.start();
Thread t2 = new Thread(h1,"2号窗口");
t2.start();
Thread t3 = new Thread(h1,"3号窗口");
t3.start();
}
@Override
public void run() {
for(int i=0;i<10;++i){
if(count >0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"count"+"正在卖"+count--);
}
}
// TODO Auto-generated method stub
}
}
运行结果:
3号窗口count正在卖5
2号窗口count正在卖4
1号窗口count正在卖4
1号窗口count正在卖3
2号窗口count正在卖1
3号窗口count正在卖2
采用同步的话,可以使用同步代码块和同步方法两种方式
[同步代码块]
语法格式:
synchronized(同步对象){
//需要同步的代码
}
但是一般都把当前对象this作为同步对象。
package thread;
public class synchronized_块 implements Runnable {
private int count = 5;
public static void main(String[] args){
synchronized_块 h1 = new synchronized_块();
Thread t1 = new Thread(h1,"1号窗口");
t1.start();
Thread t2 = new Thread(h1,"2号窗口");
t2.start();
Thread t3 = new Thread(h1,"3号窗口");
t3.start();
}
@Override
public void run() {
for(int i=0;i<10;++i){
synchronized(this){
if(count >0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"count"+"正在卖"+count--);
}
}
}
// TODO Auto-generated method stub
}
}
结果如下:
1号窗口count正在卖5
1号窗口count正在卖4
1号窗口count正在卖3
1号窗口count正在卖2
1号窗口count正在卖1
【同步方法】
也可以采用同步方法。
语法格式为synchronized 方法返回类型方法名(参数列表){
// 其他代码
}
package thread;
public class synchronized_方法 implements Runnable {
private int count = 5;
public static void main(String[] args){
synchronized_方法 h1 = new synchronized_方法();
Thread t1 = new Thread(h1,"1号窗口");
t1.start();
Thread t2 = new Thread(h1,"2号窗口");
t2.start();
Thread t3 = new Thread(h1,"3号窗口");
t3.start();
}
public synchronized void sale (){
if(count >0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"count"+"正在卖"+count--);
}
}
@Override
public void run() {
for(int i=0;i<10;++i){
sale();
}
// TODO Auto-generated method stub
}
}
结果如下:
1号窗口count正在卖5
1号窗口count正在卖4
1号窗口count正在卖3
1号窗口count正在卖2
1号窗口count正在卖1