细说Java多线程
2017-04-18 10:28
267 查看
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代表着该线程的状态;
下面是创建线程的两种方式:
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代表着该线程的状态;
相关文章推荐
- 细说Java多线程之内存可见性
- 细说Java多线程之内存可见性
- 细说java多线程之内存可见性
- 一系列1: 细说Java多线程之内存可见性
- 网络基本功(八):细说TCP滑动窗口
- 细说ASP.NET Forms身份认证
- Java多线程-并发协作(生产者消费者模型)
- Java多线程——Executor框架
- java多线程之生产者与消费者问题的简单模拟
- 细说Session
- Win8.1的IE缓存文件夹哪里去了?细说系统安装分区里那些带箭头的文件夹
- Java多线程中常见的几个问题
- Java多线程编程之ThreadLocal线程范围内的共享变量
- Opencv—第四章细说highgui课后练习4-1
- Java多线程生命周期
- JAVA多线程---1基本概念
- [转载] Codis作者黄东旭细说分布式Redis架构设计和踩过的那些坑们
- Java多线程基础学习
- 跟我学Java多线程——线程池与阻塞队列
- java多线程小结,及解决应用挂死的问题