多线程
基本概念:程序、进程、线程
一个main方法可以看作一个线程
进程可以细化为多个线程。
每个线程,拥有自己对立的:栈、程序计数器。
多个线程,共享一个线程中的结构:方法区、堆。
【注】:单核CPU也可以多线程。
线程的创建和使用
多线程的创建在java的api文档中的描述
java创建多线程的方式一:继承Thread类
1、创建一个继承于Thread的子类
2、重写 Thread 类的run()方法—>将此线程执行的操作声明在run()中
3、创建 Thread 类的子类的对象
4、通过此对象调用start()方法
/**
* @Discription: 多线程的创建,方式一:继承于Thread类
* 1、创建一个继承于 Thread 类的子类
* 2、重写 Thread 类的run()方法--->将此线程执行的操作声明在run()中
* 3、创建 Thread 类的子类的对象
* 4、通过此对象调用start()方法
*
* 例子:遍历100以内的所有偶数
*/
//创建一个继承于Thread类的子类
class MyThread extends Thread{
//重写 run() 方法
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
/*
Thread中的源码
public void run() {
if (target != null) {
target.run();
}
}
*/
}
public class ThreadTest {
public static void main(String[] args) {
//创建 Thread 类的子类的对象
MyThread t1 = new MyThread();//t1的线程是在主线程当中造的
//通过此对象调用start()方法:1、启动当前线程。2、调用当前线程的run()方法。
t1.start();//当调用start()方法执行run()方法时,t1开始独立执行
t1.run();//若直接调用run(),会先执行run()方法,后执行main方法中后面的部分,不再分线程
//如下的操作仍然是在main线程中执行的。
for(int i=0;i<100;i++){
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
//多次的执行都是不一样的结果,两个线程同时进行,结果有交互性
}
}
【注】
- 我们启动一个线程,必须调用start(),通过start()方法去调用run()方法,不能调用run()启动线程。
- 如果再启动一个线程,必须重新创建一个Thread子类对象,调用此对象的start(),不能调用同一个线程中的start方法,会导致线程异常 java.lang.IllegalThreadStateException
- run()方法的作用:如果这个线程使用单独的Runnable运行对象构造,则调用该Runnable对象的run方法; 否则,此方法不执行任何操作并返回。
- start()方法的作用:使得此线程开始执行; Java虚拟机调用此线程的run方法。
直接调用run()方法,用的都是main线程执行,没有开辟新的线程。(Thread.currentThread().getName() 输出线程的名字)
package ThreadTest;
/**
* @Discription: 多线程的创建,直接调用run方法。
*/
class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread t1 = new MyThread();
//t1.start();
t1.run();
for(int i=0;i<100;i++){
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
小练习:创建两个分线程,让其中一个线程输出1-100之间的偶数,另一个线程输出1-100之间的奇数。
package ThreadTest;
/**
* @Discription: 练习:创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程,遍历100以内的奇数
*/
public class ThreadExer {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
// MyThread2 t2 = new MyThread2();
t1.start();
// t2.start();
//创建Thread的匿名子类,通过调用其start()方法来启动线程
new Thread(){
@Override
public void run() {
for (int i=0;i<100;i++){
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}.start();
}
}
class MyThread1 extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class MyThread2 extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++){
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
Thread 的几个方法
package ThreadTest;
/**
* @Discription: 测试Thread中的常用方法:
* 1、start():启动当前线程,调用当前线程的run()方法.
* 2、run():通常需要重写Thread类中的此方法,创建的线程要执行的操作声明在此方法中。
* 3、currentThread():静态方法,返回执行当前代码的线程。
* 4、getName():获取当前线程的名字。
* 5、setName():设置当前线程的名字。
* 6、yield():释放当前CPU的执行权(有可能又分配到CPU)
* 7、join():在线程A中调用线程B的join()方法,此时线程A进入阻塞状态,直到线程B完全执行以后,线程A才结束阻塞状态。
* 8、stop():已过时,当执行此方法时,强制结束当前线程。
* 9、sleep(long millitime):静态方法,让当前线程”睡眠“(阻塞)指定的militime毫秒。在指定的militime毫秒时间内,当前线程时阻塞状态。
* 10、isAlive():判断当前线程是否存活。返回值是布尔类型
*/
class HelloThread extends Thread{
@Override
public void run() {
// Thread.currentThread().setName("线程1");//设置线程名为线程1,默认为Thread-0
for(int i=0;i<100;i++){
if (i%2==0){
try {
sleep(1000);//run()方法的父类没有抛异常,所以这里必须使用try-catch捕获异常
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
// if (i%20==0){
// yield();//释放当前cpu的执行权,
// }
}
}
public HelloThread(String name){
//带参构造器,可以通过这个构造器给线程命名
super(name);
}
public HelloThread(){
}
}
public class ThreadMethodTest {
public static void main(String[] args) {
HelloThread h1 = new HelloThread("线程1");//通过构造器给线程命名
// h1.setName("线程1");
h1.start();
Thread.currentThread().setName("主线程");//给主线程命名
for(int i=0;i<100;i++){
if (i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
if (i==20){
try {
h1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(h1.isAlive());//判断h1线程是否还存活
}
}
线程的优先级
package ThreadTest;
/**
* @Discription:线程的优先级
* 1、线程优先级的等级
* MAX_PRIORITY:10
* MIN_PRIORITY:1
* NORM_PRIORITY:5
* 2、如何获取和设置当前线程的优先级
* getPriority():获取线程的优先级
* setPriority(int p):设置线程的优先级
*
* 说明:高优先级要抢占低优先级线程的cpu的执行权,但是只是从概率上讲,高优先级的线程高概率的情况下被执行,
*/
class ThreadPriority extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
if(i%2==0