细说Java多线程

来源:互联网 发布:平安信用卡网络支付 编辑:程序博客网 时间:2024/06/05 08:41

Java中有关线程的类有两个:Thread和Runnble

下面是创建线程的两种方式:                                               

 1:继承Thread类                    

class myThread extends Thread{

...

@Overread

public void run(){

...

}

}

myThread mt=new myThread();  //创建线程

mt.run();//启动线程

2:实现Runnable接口

class myThread implements Runnable{
@Override
public void run() {

}
}

   myThread mt=new myThread();
   Thread td=new Thread(mt);
   td.start();

两种方式的区别:

Runnable方式可以避免Thread方式由于Java单继承特性带来的缺陷;

Runnable的代码可以被多个线程(Thread实例)共享,适用于多个线程处理同一资源;



通过下面的实例来分析两种方式的区别:

模拟火车站卖票的场景,假设有3个窗口卖火车票,火车票总数一共有5张;

1:继承Thread类的方式;

class MyThread extends Thread{
   private int ticketscount=5;//一共5张火车票
   private String name;//窗口,也即是线程的名字


   public MyThread(String name) {
     this.name = name;
   }


@Override
   public void run() {
while(ticketscount>0){
ticketscount--;
System.out.println(name+"卖了一张票,剩余票数"+ticketscount);
}
   }

}
public class TicketsThread {


public static void main(String[] args) {
//创建三个线程,模拟三个窗口卖票;
         MyThread mt1=new MyThread("窗口1");
         MyThread mt2=new MyThread("窗口2");
         MyThread mt3=new MyThread("窗口3");
         mt1.start();
         mt2.start();
         mt3.start();
}
}

程序的运行结果如下:

窗口3卖了一张票,剩余票数4
窗口1卖了一张票,剩余票数4
窗口1卖了一张票,剩余票数3
窗口1卖了一张票,剩余票数2
窗口1卖了一张票,剩余票数1
窗口1卖了一张票,剩余票数0
窗口2卖了一张票,剩余票数4
窗口3卖了一张票,剩余票数3
窗口2卖了一张票,剩余票数3
窗口3卖了一张票,剩余票数2
窗口2卖了一张票,剩余票数2
窗口3卖了一张票,剩余票数1
窗口2卖了一张票,剩余票数1
窗口3卖了一张票,剩余票数0
窗口2卖了一张票,剩余票数0


可以看到,每个线程中都卖了5张票,加起来一共是15张票.

2:实现Runnable接口的方式

class MyThread implements Runnable{
private int ticketscount=5;//一共5张火车票
@Override
public void run() {
while(ticketscount>0){
ticketscount--;//如果还有票,就卖掉一张;
System.out.println(Thread.currentThread().getName()+"卖了一张票,剩余票数"+ticketscount);//当前线程的名字;
}
}
}
public class TicketsRunnable {
public static void main(String[] args) {
MyThread mt=new MyThread();
Thread th1=new Thread(mt,"窗口1");
Thread th2=new Thread(mt,"窗口2");
Thread th3=new Thread(mt,"窗口3");
th1.start();
th2.start();
th3.start();
}
}

程序运行结果:

窗口1卖了一张票,剩余票数4
窗口3卖了一张票,剩余票数3
窗口2卖了一张票,剩余票数2
窗口3卖了一张票,剩余票数0
窗口1卖了一张票,剩余票数1


可以看出三个线程一共卖了5张票;


方式二的代码稍作更改之后:

class MyThread implements Runnable{
private int ticketscount=5;//一共5张火车票
@Override
public void run() {
while(ticketscount>0){
ticketscount--;//如果还有票,就卖掉一张;
System.out.println(Thread.currentThread().getName()+"卖了一张票,剩余票数"+ticketscount);//当前线程的名字;
}
}
}
public class TicketsRunnable {
public static void main(String[] args) {
MyThread mt1=new MyThread();
MyThread mt2=new MyThread();
MyThread mt3=new MyThread();
Thread th1=new Thread(mt1,"窗口1");
Thread th2=new Thread(mt2,"窗口2");
Thread th3=new Thread(mt3,"窗口3");
th1.start();
th2.start();
th3.start();
}
}


运行结果:

窗口3卖了一张票,剩余票数4
窗口2卖了一张票,剩余票数4
窗口1卖了一张票,剩余票数4
窗口2卖了一张票,剩余票数3
窗口3卖了一张票,剩余票数3
窗口2卖了一张票,剩余票数2
窗口1卖了一张票,剩余票数3
窗口2卖了一张票,剩余票数1
窗口2卖了一张票,剩余票数0
窗口3卖了一张票,剩余票数2
窗口3卖了一张票,剩余票数1
窗口3卖了一张票,剩余票数0
窗口1卖了一张票,剩余票数2
窗口1卖了一张票,剩余票数1
窗口1卖了一张票,剩余票数0

这个时候每个线程都有了5 张票;


线程的生命周期:




Java线程有两类:

1:用户线程;

     运行在前台,执行具体的任务。程序的主线程,连接网络的子线程等都是用户线程;

2 : 守护线程;

     运行在后台,为其它前台线程服务;

     特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作;

     应用:数据库连接池中的监测线程;

                JVM虚拟机启动后的监测线程;

    最常见的守护线程:垃圾回收线程;

    如何设置守护线程:可以通过调用Thread类的setDaemon(true)方法来设置当前的线程为守护线程;

    注意事项:setDaemon(true)必须在start()方法执行前调用;

                        在守护线程中产生的线程也是守护线程;

                        不是所有的任务都可以分配给守护线程来执行,比如读写操作与计算逻辑;


使用jstack生成线程快照:

jatack的作用:生成当前时刻线程的快照,(threaddump,即当前进程中所有线程的信息);

               目的:帮助定位程序问题出现的原因,如长时间停顿,cpu占用率过高等;

            使用方法:打开命令行,键入 jstack可以看到提示使用方式,键入jstack -l pid  可以查看线程id为pid的快照,如下图:

daemon代表是守护线程,java.lang.Thread.State代表着该线程的状态;

0 0
原创粉丝点击