多线程
在讲线程之前,我们应该先了解一下什么是进程?
进程:系统可以进行独立调配并且它是一个不可分割 独立单元
例如(我们手机或者电脑后台运行的软件,客户端等等,它们就是进程)
线程:线程是进程中一个独立的单元,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间。
例如:(我们的电脑管家可以进行杀毒和清理垃圾,其中的杀毒和清理垃圾功能就可以看做事线程)
多线程:像上面所说的电脑管家,当我们同时执行清理垃圾和杀毒功能,虽然表面看起来是可以同步进行的,但实际不是同步进行的,只是每个线程在抢占CPU的执行权,这就是多线程。
多线程的意义:为了提高CPU的使用率,
线程之间都在抢占CPU的执行权,而且多线程的执行是随机的
要想实现多线程程序,需要开启进程,开启进程就需要创建系统资源,但是只有c/c++可以创建资源,所我们我们可以在底层利用c创建好的系统资源来实现
并发和并行的区别:
并发是指同一个时间点,物理逻辑上的
并行指的是同一个时间段。
让我们来看看多线程的实现:
首先我们需要创建一个子类去实现Thread类,并且要重写该类的run方法
package com.westos.Thread;
public class MyThread extends Thread{
/*public MyThread(String name) {
super(name);
}*/
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
}
}
创建一个实现类去实现多线程,这是给线程设置名字的两种方式:
package com.westos.Thread;
public class ThreadDome {
/**
* @param args
* 给线程设置名字的两种方式
* 使用方式1时:可以不在MyThread类中添加无参构造,因为系统默认访问无参构造
* 当你使用第二种方式时,就必须要添加有参构造了,否则就会报错
*/
public static void main(String[] args) {
//方式1:无参+setName()方法
//创建MyThread类对象
MyThread mt=new MyThread();
MyThread mt2=new MyThread();
//setName方法
mt.setName("迪丽热巴");
mt2.setName("井杰");
//开始运行
mt.start();
mt2.start();
//方式2:直接MyThread类的有参构造
/*//创建MyThread类对象
MyThread mt=new MyThread("迪丽热巴");
MyThread mt2=new MyThread("井杰");
//开始运行
mt.start();
mt2.start();
*/
}
}
线程的一些方法:
等待该线程终止:
public final void join()throws InterruptedException等待该线程终止。
返回正在执行的线程:
public static Thread currentThread()返回对当前正在执行的线程对象的引用。
package com.westos.Thread01;
public class ThreadJoin extends Thread{
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
}
}
package com.westos.Thread01;
public class ThreadDome {
public static void main(String[] args) {
//创建三个ThreadJoin类对象
ThreadJoin tj=new ThreadJoin();
ThreadJoin tj2=new ThreadJoin();
ThreadJoin tj3=new ThreadJoin();
//设置名字
tj.setName("刘备");
tj2.setName("张飞");
tj3.setName("关羽");
tj.start();
//public final void join()throws InterruptedException等待该线程终止。
try {
tj.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
/*//public static Thread currentThread()返回对当前正在执行的线程对象的引用。
System.out.println(Thread.currentThread().getName());
运行的结果是:main(该方法返回的是正在执行的主线程,而tj和tj2是主线程的两个子线程)
*/
}
}
暂停线程:
public static void yield()暂停当前正在执行的线程对象,并执行其他线程
package com.westos.Thread02;
public class Threadyield extends Thread{
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
//public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
Thread.yield();
}
}
package com.westos.Thread02;
public class YieldDome {
public static void main(String[] args) {
//创建Threadyield类对象
Threadyield ty=new Threadyield();
Threadyield ty2=new Threadyield();
//设置名字
ty.setName("蜘蛛侠");
ty2.setName("钢铁侠");
//开始运行
ty.start();
ty2.start();
}
}
守护线程:
public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程
package com.westos.Thread03;
public class ThreadsetDaemon extends Thread{
public void run() {
for(int x=0;x<100;x++) {
System.out.println(getName()+":"+x);
}
}
}
package com.westos.Thread03;
/**
* @author 杰哥
*调用setDaemon方法时,必须有主线程一起启动,否则无法编译
*/
public class setDaemonDome {
public static void main(String[] args) {
//创建ThreadsetDaemon类对象
ThreadsetDaemon td=new ThreadsetDaemon();
ThreadsetDaemon td2=new ThreadsetDaemon();
td.setName("雅妃");
td2.setName("美杜莎");
//public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。
//当正在运行的线程都是守护线程时,Java 虚拟机退出。
//该方法必须在启动线程前调用。 值为true时表示正常
td.setDaemon(true);
td2.setDaemon(true);
//启动线程
td.start();
td2.start();
Thread.currentThread().setName("萧炎");
for(int i=0;i<5;i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
休眠:
public static void sleep(long millis) throws InterruptedException
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),
package com.westos.Thread03;
/**
* @author 杰哥
*调用setDaemon方法时,必须有主线程一起启动,否则无法编译
*/
public class setDaemonDome {
public static void main(String[] args) {
//创建ThreadsetDaemon类对象
ThreadsetDaemon td=new ThreadsetDaemon();
ThreadsetDaemon td2=new ThreadsetDaemon();
td.setName("雅妃");
td2.setName("美杜莎");
//public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。
//当正在运行的线程都是守护线程时,Java 虚拟机退出。
//该方法必须在启动线程前调用。 值为true时表示正常
td.setDaemon(true);
td2.setDaemon(true);
//启动线程
td.start();
td2.start();
Thread.currentThread().setName("萧炎");
for(int i=0;i<5;i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package com.westos.Thread04;
public class ThreadsleepDome {
public static void main(String[] args) {
//创建对象
ThreadSleep ts=new ThreadSleep();
ThreadSleep ts2=new ThreadSleep();
ts.setName("张三");
ts2.setName("李四");
ts.start();
ts2.start();
}
}
stop():直接停止线程执行
interrupt():中断线程。
package com.westos.Thread05;
public class ThreadStopInterrupt extends Thread{
public void run() {
System.out.println("程序开始了...");
//睡眠10秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("程序出现中断异常...");
}
System.out.println("程序结束了...");
}
}
package com.westos.Thread05;
public class StopInterruptDome {
public static void main(String[] args) {
ThreadStopInterrupt tsi=new ThreadStopInterrupt();
tsi.start();
try {
tsi.sleep(3000);
//表示停止
// tsi.stop();
//中断线程
tsi.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
前面我们学习了多线程的实现,除了上面继承Thread类的这种方式呢,还有一种实现Runnable接口的方法,它也可以进行多线程的实现,但是其中的一些方法发生了改变,需要我们注意:
package com.westos.Runable;
/**
* @author 杰哥
*实现多线程的第二种方式:实现Runable接口
*/
public class RunnableDome implements Runnable{
public void run() {
for(int x=0;x<100;x++) {
//因为这是第二种方式,不是之前的继承Thread方式,所以不能直接调用getName方法
//Thread.currentThread()返回的是正在运行的线程
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
package com.westos.Runable;
public class RunnableTest {
public static void main(String[] args) {
//创建RunableDome类对象
RunnableDome rd=new RunnableDome();
/**
* Thread(Runnable target, String name) 分配新的 Thread 对象。
* 这是Thread类有关Runnable接口的一种构造方法
*/
Thread t1=new Thread(rd,"杨过");
Thread t2=new Thread(rd,"小龙女");
t1.start();
t2.start();
}
}