Java多线程

本文介绍了Java中的多线程概念,包括线程的实现方式,如继承Thread类和实现Runnable接口,以及线程的主要操作,如命名、休眠和优先级设置。详细探讨了线程的启动、状态和相关方法,帮助开发者理解Java多线程编程。

目录

1.1、多线程的基本概念

1.2、多线程的实现(重点)

1.2.1、继承Thread类实现多线程

1.2.2、实现Runnable接口实现多线程

1.2.4、线程的操作状态

1.3、线程的主要操作方法

1.3.1、线程的命名和取得

1.3.2、线程的休眠

1.3.3、线程的优先级

1.1、多线程的基本概念

                如果要想解释多线程,那么首先应该从单进程开始讲起,最早的DOS系统有一个最大的特征:一旦电脑出现了病毒,电脑会立刻死机,因为传统DOS系统属于单进程的处理方式,即:在同一个时间段上只能有一个程序执行。后来到了windows时代,电脑即使(非致命)存在了病毒,那么也可以正常使用,只是慢一些而已,因为windows属于多进程的处理操作,但是这个时候的资源依然只有一块,所以在同一个时间段上会有多个程序共同执行,而在一个时间点上只能有一个程序在执行,多线程是在一个进程基础之上的进一步划分,因为进程的启动所消耗的时间是非常长的,所以在进程之上的进一步的划分就变得非常重要,而且性能也会有所提高。

                所有的线程一定要依附于进程才能够存在,那么进程一旦消失了,线程也一定会消失,但是反过来不一定。而Java是为数不多的支持多线程的开发语言之一。

1.2、多线程的实现(重点

                在Java之中,如果要想实现多线程的程序,那么就必须依靠一个线程的主体类(就好比主类的概念一样,表示的是一个线程的主类),但是这个线程的主体类在定义的时候也需要有一些特殊的要求,这个类可以继承Thread类或实现Runnable接口来完成定义。

1.2.1、继承Thread类实现多线程

                java.lang.Thread是一个负责线程操作的类,任何的类只需要继承了Thread类就可以成为一个线程的主类,但是既然是主类必须有它的使用方法,而线程启动的主方法是需要覆写Thread类中的run()方法才可以。

范例:定义一个线程的主体类

lass MyThread extends Thread { // 线程的主体类
	private String title;
	public MyThread(String title) {
		this.title = title;
	}
	@Override
	public void run() { // 线程的主方法
		for (int x = 0; x < 50; x++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
}
public class TestDemo {
	public static void main(String[] args) throws Exception {
		MyThread mt1 = new MyThread("线程A") ;
		MyThread mt2 = new MyThread("线程B") ;
		MyThread mt3 = new MyThread("线程C") ;
		mt1.run() ;
		mt2.run() ;
		mt3.run() ;
	}
}

                但是以上的操作实话而言并没有真正的启动多线程,因为多个线程彼此之间的执行一定是交替的方式运行,而此时是顺序执行,即:每一个对象的代码执行完之后才向下继续执行。如果要想在程序之中真正的启动多线程,必须依靠Thread类的一个方法:public void start(),表示真正启动多线程,调用此方法后会间接调用run()方法。

public class TestDemo {
	public static void main(String[] args) throws Exception {
		MyThread mt1 = new MyThread("线程A") ;
		MyThread mt2 = new MyThread("线程B") ;
		MyThread mt3 = new MyThread("线程C") ;
		mt1.start() ;
		mt2.start() ;
		mt3.start() ; 
	}
}

                此时可以发现,多个线程之间彼此交替执行,但是每次的执行结果肯定是不一样的。通过以上的代码就可以得出结论:要想启动线程必须依靠Thread类的start()方法执行,线程启动之后会默认调用了run()方法

1.2.2、实现Runnable接口实现多线程

                使用Thread类的确是可以方便的进行多线程的实现,但是这种方式最大的缺点就是单继承的问题,为此,在java之中也可以利用Runnable接口来实现多线程,而这个接口的定义如下:

public interface Runnable {
	public void run();
}

范例:通过Runnable接口实现多线程

class MyThread implements Runnable { // 线程的主体类
	private String title;
	public MyThread(String title) {
		this.title = title;
	}
	@Override
	public void run() { // 线程的主方法
		for (int x = 0; x < 50; x++) {
			System.out.println(this.title + "运行,x = " + x);
		}
	}
}

                这个时候和之前的继承Thread类区别不大,但是唯一的好处就是避免了单继承局限,不过现在问题也就来了。刚刚解释过,如果要想启动多线程依靠Thread类的start()方法完成,之前继承Thread类的时候可以将此方法直接继承过来使用,但现在实现的是Runable接口,没有这个方法可以继承了,为了解决这个问题,还是需要依靠Thread类完成,在Thread类中定义了一个构造方法:public Thread(Runnable target),接收Runnable接口对象。

范例:利用Thread类启动多线程

1.2.4、线程的操作状态

每一个线程对象实际上都拥有属于自己的运行状态,那么下面分别说明线程的每种运行状态的特点:

1、 所有的线程对象都必须通过关键字new进行创建;

2、 线程如果要进行启动则一定会调用Thread类的start()方法,但是代码可能会分先后顺序:

new Thread(mt).start();

new Thread(mt).start();

new Thread(mt).start();

以上是启动了三个线程,虽然在代码上有先后调用start()方法的顺序,可是对于JVM而言,都表示着所有的线程将同时进入到就绪状态,等待执行。

3、 进入到就绪状态之后,将等待着CPU进行资源的抢占,抢占到了资源之后,线程会进如到运行状态,开始执行run()方法体之中所定义的代码,;

4、 每一个线程执行run()方法到一定的时间的时候会让出CPU资源,进入到阻塞状态,而后重新回到就绪状态等待下次资源调度并继续执行run()方法中的代码;

5、 如果全部方法执行完毕之后,将进入到线程的终止状态,并且不会再进入到就绪状态,直接结束。

1.3、线程的主要操作方法

线程对象的也是可以进行若干种操作的,而且所有的线程操作方法都在Thread类中定义

1.3.1、线程的命名和取得

线程本身是属于不可见的运行状态的,即:每次操作的时候是无法预料的,所以如果要想在程序之中操作线程,唯一依靠的就是线程名称,而要想取得和设置线程的名称可以使用如下的方法:

· 构造方法:public Thread(Runnable target, String name);

· 设置名字:public final void setName(String name);

· 取得名字:public final String getName()。

                但是由于线程的状态不确定,所以每次可以操作的都是正在执行run()方法的线程,那么取得当前线程对象的方法:public static Thread currentThread()。

范例:线程的命名和取得

class MyThread implements Runnable { // 线程的主体类
	@Override
	public void run() { // 线程的主方法
		System.out.println(Thread.currentThread().getName());
	}
}
public class TestDemo {
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt).start();	// Thread-0
		new Thread(mt).start();	// Thread-1
		new Thread(mt).start();	// Thread-2
		new Thread(mt,"线程A").start();	// 线程A
		new Thread(mt,"线程B").start();	// 线程B
	}
}

                如果说现在为线程设置名字的话,那么会使用用户定义的名字,而如果没有设置线程名称,会自动的为其分配一个名称,这一点操作和之前的static命名类似。

问题:一个JVM进程启动的时候至少启动几个线程呢?

两个线程:main、gc。

1.3.2、线程的休眠

        线程的休眠指的是让程序的执行速度变慢一些,方法:public static void sleep(long millis) throws InterruptedException,设置的休眠单位是毫秒。

  • static void sleep(long millis)(指定时间:毫秒)

        令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后

重排队。

class MyThread implements Runnable { // 线程的主体类
	@Override
	public void run() { // 线程的主方法
		for (int x = 0; x < 100; x++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ",x = " + x);
		}
	}
}
public class TestDemo {
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "线程A").start();
		new Thread(mt, "线程B").start();
		new Thread(mt, "线程C").start();
		new Thread(mt, "线程D").start();
		new Thread(mt, "线程E").start();
	}
}

                这个时候由于电脑的执行速度原因,所有的线程先后顺序并不容易发现,但是可以发现休眠了之后,程序运行速度变慢了。

一张趣图

1.3.3、线程的优先级

 从理论上讲,线程的优先级越高,越有可能先执行。如果要想操作线程的优先级有如下两个方法:

· 设置线程的优先级:public final void setPriority(int newPriority);

· 取得线程的优先级:public final int getPriority();

发现设置和取得优先级的时候都是利用了一个int型数据的操作,而这个int型数据有三种取值:

· 最高优先级:public static final int MAX_PRIORITY10

· 中等优先级:public static final int NORM_PRIORITY5

· 最低优先级:public static final int MIN_PRIORITY1

范例:设置优先级

class MyThread implements Runnable { // 线程的主体类
	@Override
	public void run() { // 线程的主方法
		for (int x = 0; x < 10; x++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ",x = " + x);
		}
	}
}
public class TestDemo {
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		Thread t1 = new Thread(mt,"线程A") ;
		Thread t2 = new Thread(mt,"线程B") ;
		Thread t3 = new Thread(mt,"线程C") ;
		t3.setPriority(Thread.MAX_PRIORITY) ;
		t1.setPriority(Thread.MIN_PRIORITY) ;
		t2.setPriority(Thread.MIN_PRIORITY) ;
		t1.start() ;
		t2.start() ;
		t3.start() ;
	}
}

问题:主线程的优先级是什么呢?

public class TestDemo {
	public static void main(String[] args) throws Exception {
		System.out.println(Thread.currentThread().getPriority());
	}
}

发现主线程的优先级是5,是中等级别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值