添砖加瓦(java)
多线程
前言:
大家好我是kdy丶
这里写目录标题
一丶程序、进程、线程:
1丶基本概念:
1丶 程序(program)
概念:是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码。
2丶 进程(process)
概念:程序的一次执行过程,或是正在运行的一个程序。
说明:进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
3丶 线程(thread)
概念:进程可进一步细化为线程,是一个程序内部的一条执行路径。
说明:线程作为调度和执行的单位,每个线程拥独立的运行栈和程序计数器(pc),线程切换的开小。
也就是说进程是包括多线程的。
这是一场进程分别为多线程的和单线程的概念图。
我们可以举例子来说明:
就像是我们启动的电脑管家就是一个进程,
而我们电脑管家把这些功能同时开启就是多线程。
二丶多线程的创建:
1丶方式一:继承Thread类的方式:
1丶创建多线程的大致步骤:
1丶创建一个继承于Thread类的子类
2丶重写Thread类的run() 之后将此线程执行的操作声明在run()中
3丶创建Thread类的子类的对象
4丶通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
例:
public class demo01 {
public static void main(String[] args) {
mythread mt=new mythread();
mt.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 100; i++) {
if(i%2!=0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
class mythread extends Thread{
@Override
public void run() {
Thread.currentThread().setName("线程k1");
for (int i = 0; i < 100; i++) {
if(i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
运行结果:
我们可以看到,运行出来的结果并不是有规律性的,这就是多线程 ,可能没启动一次都会有不一样的执行结果。
在这里可能大家都会想为什么调用的是start()方法而不是run()方法?其实道理很简单,再主方法中我们无论是创建对象的还是调用方法其实都是在主线程中运行的,是主线程帮我们弄。,因为start():①启动当前线程 ② 调用当前线程的run()的这两个特性功能,开辟的另一条线程。如果我们调用的是run()方法,那么他不会开辟新的线程,run方法还是归为主线程中。
2丶假如我们要如果再启动一个线程,我们要怎么样做?
如果我再次调用 mt.start();
运行结果:
那我们改怎么做?
必须只能重新创建一个Thread子类的对象,调用此对象的start().
2丶Thread类的相关方法:
1丶相关方法:
1丶start():启动当前线程;调用当前线程的run()
2丶 run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3丶currentThread():静态方法,返回执行当前代码的线程
4丶 getName():获取当前线程的名字
5丶setName():设置当前线程的名字
6丶yield():释放当前cpu的执行权
我们来看这样一段代码:
public class demo02 {
public static void main(String[] args) {
yy y=new yy();
y.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
class yy extends Thread{
@Override
public void run() {
Thread.currentThread().setName("线程k1");
for (int i = 0; i < 20; i++) {
if (i==5){
yield();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
运行结果:
可以看到当我们的线程k1执行到i=5时,就执行了主线程,其实这并不是巧合,而是在线程k1执到i=5的时候,调用了 yield();方法,释放了当前cpu的执行权。主线程才有几率执行。但这不等于让给主线程执行,一旦主线程没来得及执行,那么执行的还是线程k1例的程序。
这就好比,我们排队买奶茶,如果轮到了我,我可以组织一场竞赛,同时抢答问题,谁先出回答出来谁就占据我的位置,执行你的操作,无论是谁都有机会。
7丶 join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态。
例:
public class demo02 {
public static void main(String[] args) {
yy y=new yy();
y.start();
Thread.currentThread().setName("主线程");
for (int i = 0; i < 20; i++) {
if (i==10) {
try {
y.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
class yy extends Thread{
@Override
public void run() {
Thread.currentThread().setName("线程k1");
for (int i = 0; i < 20; i++) {
if (i==5){
// yield();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
运行结果:
我们在主线程中调用了我们的线程k1,在我们运行到i=10的时候,主线程阻塞,必须要全部等线程k1全部执行完之后才可以进行主线程。
8丶sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态。
9丶 isAlive():判断当前线程是否存活
2丶线程的优先级:
线程的优先级:
MAX_PRIORITY:10
MIN _PRIORITY:1
NORM_PRIORITY:5 (默认优先级)
获取和设置当前线程的优先级:
getPriority():获取线程的优先级
setPriority(int p):设置线程的优先级
说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只当高优先级的线程执行完以后,低优先级的线程才执行。
3丶方式二:实现Runnable接口的方式:
大致步骤:
1丶 创建一个实现了Runnable接口的类
2丶实现类去实现Runnable中的抽象方法:run()
3丶创建实现类的对象
4丶将此对象作为参数传递到Thread类的构造器Thread(Runnable target)中,创建Thread类的对象
5丶通过Thread类的对象调用start()
public class demo03 {
public static void main(String[] args) {
mythread1 m=new mythread1();
Thread thread=new Thread(m);
thread.start();
for