多线程-创建,API操作,状态转换

多线程

1,什么是进程,什么是线程

  • 1,进程:

    • 系统中运行的一个程序,程序一旦运行起来就是进程
  • 2,线程:

    • 它被包含在进程之中,是进程中的实际运行单位,一条线程指的是进程中的一个单一顺序的控制流。
    • 一个进程中可以并发多个线程,每一条线程并行执行不同的任务。

并发和并行

  • 并发:cpu一核,多线程操作同一个资源
  • 并行:cpu多核,多个线程可以同时执行。

程序的运行原理

  • 分时调度:所有线程轮流使用cpu的使用权
  • 抢占式调度:优先让优先级最好的线程使用cpu,如果线程的优先级相同,那么cpu随机挑选一个执行,Java使用的为抢占式调度。不提高程序的运行速度,但能够提高程序的运行效率

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记一个守护程序。当某个线程中运行的代码创建一个Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

守护程序:守护线程,是指在程序运行时 在后台提供一种通用服务的线程,这种线程并不属于程序中不可或缺的部分。通俗点讲,任何一个守护线程都是整个JVM中所有非守护线程的"保姆"。

创建线程的实现方式。

继承Thread类

  • 一个声明为Thread的子类,这个子类重写了Thread的run()方法,然后可以分配启动子类的实例。
  • start()方法启动多线程,需要用继承Thread类的类对象来启动它,run()方法里是多线程的执行体。
public class DemoSon1 extends Thread{
    public static void main(String[] args) throws Exception{
        //new DemoSon1().run();
        //currentThread()返回当前执行的对象名
        System.out.println(new Thread().currentThread().getName());
        DemoSon1 demoSon1 = new DemoSon1();
        //start()在主方法启动时调用重写的run方法
        demoSon1.start();

        for(int i =0 ; i<10;i++){
            System.out.println("主方法执行了"+i);
            Thread.sleep(1000);
        }
    }
    public void run() {
        //返回当前线程的名字
        System.out.println("当前线程的名字"+this.getName());
        for(int i =0 ; i<10;i++){
            System.out.println("run方法执行了"+i);
            try {
                //线程休眠
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printstacktrace();
            }
        }
    }
}


//运行结果:
main
主方法执行了0
当前线程的名字Thread-1
run方法执行了0
run方法执行了1方法执行了1
run方法执行了2方法执行了2
run方法执行了3方法执行了3方法执行了4
run方法执行了4方法执行了5
run方法执行了5
run方法执行了6方法执行了6方法执行了7
run方法执行了7
run方法执行了8方法执行了8方法执行了9
run方法执行了9

实现runnable接口

  • 声明一个实现Runnable接口的类,这个类实现了run()方法,可以分配类的实例,在创建Thread时作为参考,并启动
  • 重写run()方法,启动时需要创建Thread类对象,同时创建时还要将实现Runnable接口的类对象放进去,再使用Thread类对象调用start()方法启动多线程
public class DemeSon implements Runnable{
    public static void main(String[] args)  {

        DemeSon demeSon = new DemeSon();
        Thread thread = new Thread(demeSon);
        thread.start();
        for (int i=0;i<10;i++){
            System.out.println("主方法线程"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printstacktrace();
            }

        }
    }
    @Override
    public void run() {
        //返回当前线程的名字
        System.out.println("当前线程的名字"+new Thread().getName());
        for(int i =0 ; i<10;i++){
            System.out.println("run方法执行了"+i);

                //线程休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printstacktrace();
            }

        }
    }
}


//执行结果方法线程0
当前线程的名字Thread-1
run方法执行了0方法线程1
run方法执行了1
run方法执行了2方法线程2方法线程3
run方法执行了3方法线程4
run方法执行了4
run方法执行了5方法线程5
run方法执行了6方法线程6
run方法执行了7方法线程7
run方法执行了8方法线程8方法线程9
run方法执行了9

实现callable接口

  • 声明一个实现Callable()方法的类,它是有返回值的,这个类需要重写call方法
public class Demo implements Callable<Boolean>{//返回布尔类型的值

    public static void main(String[] args) throws Exception {
        Demo demo = new Demo();
        demo.call();
    }

    @Override
    public Boolean call()  {
        //返回当前线程的名字
        System.out.println("当前线程的名字"+new Thread().getName());
        for(int i =0 ; i<10;i++){
            System.out.println("run方法执行了"+i);

            //线程休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printstacktrace();
            }

        }
        return true;
    }
}

//执行结果
当前线程的名字Thread-0
run方法执行了0
run方法执行了1
run方法执行了2
run方法执行了3
run方法执行了4
run方法执行了5
run方法执行了6
run方法执行了7
run方法执行了8
run方法执行了9

Thread和Runnable的区别

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

总结:

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

线程操作API

isAlive

/**
* 测试此线程是否活动。如果线程已经启动并且还没有死亡,那么线程就是活的。
*
* 线程存活返回true,死亡返回false
*/
public final native boolean isAlive();
//查看threadDemo线程是否存活
boolean a = threadDemo.isAlive();
System.out.println(a);

setPriority

/**
* setPriority: 更改线程的优先级
* 参数说明:
*		newPriority:将线程设置为的优先级
*		
*/
public final void setPriority(int newPriority)
//将threadDemo线程顺序设为1
threadDemo.setPriority(1);

getPriority

/**
* 返回此线程的优先级。
*/
public final int getPriority()
package com.it.www.threadapp;

public class Demo3 {

	public static void main(String[] args) {
		
		MyThread03   mt1 = new  MyThread03("T1");
		MyThread03   mt2 = new  MyThread03("T2");
		MyThread03   mt3 = new  MyThread03("T3");
		
		//设置线程的优先级
		mt1.setPriority(10);
		mt2.setPriority(Thread.norM_PRIORITY);
		mt3.setPriority(Thread.MIN_PRIORITY);
		
		//启动三个子线程
		mt1.start();
		mt2.start();
		mt3.start();
		
		//线程是存在一个执行的优先级别,是通过一个数值来进行表示的,数值越大,执行的优先级就越高
		int   priv1 = mt1.getPriority();
		int   priv2 = mt2.getPriority();
		int   priv3 = mt3.getPriority();
		
		//每个新创建的线程,认的优先级是 5  ,其范围是1----10。
		System.out.println(priv1+"-----"+priv2+"----"+priv3);

	}

}
//定义一个线程类
class    MyThread03  extends  Thread{
	
	//通过构造的形式给线程取个名称
	public  MyThread03(String  name){
		super(name);
	}
	
	@Override
	public void run() {
		
		for(int i=1;i<=5;i++){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printstacktrace();
			}
			System.out.println(Thread.currentThread().getName()+"-----------"+i);
		}
		
	}
	
}

提示

线程的执行与否,关联到许多的因素,其中线程的优先级也是执行机会提升的一个很重要的因素,但是并不是绝对性的,也就说不一定就是优先级高的线程首先执行完毕。

sleep

/**
* 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,取决于系统定时器和调度程序的精度和准确性。
* 线程不会失去任何显示器的所有权 
*/
public static native void sleep(long millis) throws InterruptedException;
//设置线程休眠时间:2000毫秒
Thread.sleep(2000);

join

/**
* 等待线程等待。
*/
public final void join() throws InterruptedException 
package com.it.www.threadapp;

public class Demo4 {

	public static void main(String[] args) {

		// 创建一个子线程
		MyThread04 mt1 = new MyThread04("T1");
		// 启动三个子线程
		mt1.start();

		for (int i = 1; i <= 5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printstacktrace();
			}
			System.out.println(Thread.currentThread().getName() + "-----------"
					+ i);
		}

	}

}

// 定义一个线程类
class MyThread04 extends Thread {

	// 通过构造的形式给线程取个名称
	public MyThread04(String name) {
		super(name);
	}

	@Override
	public void run() {

		for (int i = 1; i <= 5; i++) {
			if (i == 3) {
				try {
					//合并线程(当前这个子线程被合并了,就是后续的操作不再执行,回到未执行完毕的主线程上继续以单线程的形式进行执行)
					this.join();
				} catch (InterruptedException e) {
					e.printstacktrace();
				}
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printstacktrace();
			}
			System.out.println(Thread.currentThread().getName() + "-----------"
					+ i);
		}
	}
}

yield

/**
* 暂停当前正在执行的线程对象,并执行其他线程
*/
public static native void yield();
package com.it.www.threadapp;

public class Demo5 {

	public static void main(String[] args) {

		// 创建一个子线程
		MyThread05 mt1 = new MyThread05("T1");
		// 启动三个子线程
		mt1.start();

		for (int i = 1; i <= 5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printstacktrace();
			}
			System.out.println(Thread.currentThread().getName() + "-----------"
					+ i);
		}

	}

}

// 定义一个线程类
class MyThread05 extends Thread {

	// 通过构造的形式给线程取个名称
	public MyThread05(String name) {
		super(name);
	}

	@Override
	public void run() {

		for (int i = 1; i <= 5; i++) {
			if (i == 3) {
					//让出执行权,其他线程可以获取cpu的执行权,从而进行执行,但是也有可能,当前这个线程再次获取到执行权,继续进行执行;
					this.yield();
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printstacktrace();
			}
			System.out.println(Thread.currentThread().getName() + "-----------"
					+ i);
		}

	}
}

stop

/**
* 强制使正在运行的线程停止运行(已停用)
*/
public final void stop() {}
if (a==55){
    this.stop();//当执行到55的时强制停止线程
}

wait 、 notify 、 notifyAll

都是用于控制线程同步的方法,后面进行讲解。

线程状态转换

图示结构:

在这里插入图片描述

说明:

线程共有5种状态: 创建 、 就绪状态 、 运行状态 、 阻塞状态 、 死亡状态

创建好一个线程之后,调用start方法并不是就进入了运行状态,而是进入了就绪状态(就是具备线程执行的一切条件)。再操作系统的分配中才会进入到执行的状态。由于各种情况可能会导致阻塞,解除阻塞后进入的是就绪状态,再进入到运行的状态。

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...