文章目录
Process与Threa
说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运
行的含义,是一个静态的概念。
而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单
位
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没
有存在的意义。线程是CPU调度和执行的的单位。
注意
很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
进程、线程 概念:
线程就是独立的执行路径;
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()称之为主线程,为系统的入口,用于执行整个程序;
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的。
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;
线程会带来额外的开销,如cpu调度时间,并发控制开销。
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
线程开启不一定立即执行,由CPU调度执行
关于多线程的测试demo
例:
package cmd.kuang.demo1;
/**
* @description: 创建线程方式:继承Thread,重写run方法,调用start开启线程
* @auther: LYH
* @Date: 2022/5/5 11:35
* @version: 1.0
* @modified By:
*/
public class TestThread extends Thread{
@Override
public void run(){
for (int i = 0;i<20;i++){
System.out.println("测试我这看代码----"+i);
}
}
public static void main(String[] args) {
//创建一个线程对象
TestThread testThread = new TestThread();
//调用start方法开启线程
testThread.start();
for (int i = 0; i < 20; i++) {
System.out.println("学习多线程--"+i);
}
}
}
创建多线程方法二
实现runnable接口重新run方法
package cmd.kuang.demo1;
/**
* @description: 练习Thread,实现runnable接口
* @auther: LYH
* @Date: 2022/5/5 20:07
* @version: 1.0
* @modified By:
*/
public class TestThread2 implements Runnable{
@Override
public void run(){
for (int i = 0;i<20;i++){
System.out.println("测试我这看代码----"+i);
}
}
public static void main(String[] args) {
//创建runnbale接口的实现类
TestThread2 testThread2 = new TestThread2();
//创建线程对象,通过线程对象来开启我们的线程,代理
// Thread thread = new Thread(testThread2);
// thread.start();
//开启线程
new Thread(testThread2).start();
for (int i = 0; i < 20; i++) {
System.out.println("学习多线程--"+i);
}
}
}
继承Thread类(上面实例1)
子类继承Thread类具备多线程能力
启动线程:子类对象.start()
不建议使用:避免OOP单继承局限性
实现Runnable接口(上面实例2)
实现接口Runnable具有多线程能力
启动线程:传入目标对象+Thread对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
关于龟兔赛跑的案例
package cmd.kuang.demo1;
/**
* @description: 龟兔赛跑例子
* @auther: LYH
* @Date: 2022/5/7 20:10
* @version: 1.0
* @modified By:
*/
public class Race implements Runnable {
//胜利者
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子") && i%10==0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断是否结束
boolean flag = gameOver(i);
//如果比赛结束,就停止
if (flag){
break;
}
System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");
}
}
//判断是否完成比赛
private boolean gameOver(int steps) {
//判断是否有胜利者
if (winner != null) {//已存在胜利者
return true;
}
if (steps == 100) {
winner = Thread.currentThread().getName();
System.out.println("winner is" + winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
了解Callble接口
实现Callable接口,需要返回值类型
重写call方法,需要抛出异常
创建目标对象 创建执行服务:ExecutorServiceser=Executors.newFixedThreadPool(1);
提交执行:Futureresult1=ser.submit(t1);
获取结果:boolean r1=result1.get()
关闭服务:ser.shutdownNow();
关于代理的例子
package cmd.kuang.demo1;
/**
* @description: 代理测试
* @auther: LYH
* @Date: 2022/5/9 14:46
* @version: 1.0
* @modified By:
*/
//静态代理总结
//真实对象和代理对象都要实现同一个接口
//代理对象必须要代理真实角色。
//好处,代理对象可以做很多代理对象做不了的事情
//真实对象专注做自己的事情
public class StacticProxy {
public static void main(String[] args) {
You you = new You();
new Thread(()-> System.out.println("测试")).start();
new WeddingCompany(new You()).HappyMarry();
WeddingCompany weddingCompany = new WeddingCompany(you);
weddingCompany.HappyMarry();
}
}
interface Marry {
void HappyMarry();
}
//真实的角色
class You implements Marry {
@Override
public void HappyMarry() {
System.out.println("开心");
}
}
//代理角色
class WeddingCompany implements Marry {
//代理谁--》真实目标角色
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
after();
this.target.HappyMarry();//这就是真实对象
before();
}
private void after() {
System.out.println("之前,布置现场");
}
private void before() {
System.out.println("之后,收尾款");
}
}
线程的五大状态
线程停止
● 不推荐使用JDK提供的stop()、destroy()方法。【已废弃】
● 推荐线程自己停止下来
● 建议使用一个标志位进行终止变量当flag=false,则终止线程运行。
package cmd.kuang.demo1;
/**
* @description: 线程停止方法
* @auther: LYH
* @Date: 2022/5/13 14:42
* @version: 1.0
* @modified By:
*/
//建议线程正常停止--->利用次数,不建议死循环。
//建议使用标志位--->设置一个标志位
//不要使用stop或者destroy等过时或者JDK不建议使用方法
public class TestStop implements Runnable{
//1、设置一个标示位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run.....Thread"+i++);
}
}
//2、设置一个公开的方法停止线程,转换标示位
public void stop(){
this.flag = false;
}
public static void main(String[] args){
TestStop testStop = new TestStop();
//线程开始
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if (i==900){
//调用stop方法切换标志位,让线程停止
testStop.stop();
System.out.println("线程停止");
break;
}
}
}
}
线程休眠
sleep(时间)指定当前线程阻塞的毫秒数;
sleep存在异常InterruptedException;
sleep时间达到后线程进入就绪状态;
sleep可以模拟网络延时,倒计时等。
每一个对象都有一个锁,sleep不会释放锁;
利用sleep模拟倒计时,还有打印当前时间
package cmd.kuang.demo1;
import javax.xml.crypto.Data;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @description: 模拟倒计时
* @auther: LYH
* @Date: 2022/5/14 11:32
* @version: 1.0
* @modified By:
*/
public class TestSleep2 {
public static void main(String[] args) {
//打印当前系统时间
Date starTime = new Date(System.currentTimeMillis());//获取当前时间
while (true){
try {
Thread.sleep(1000);
//输出时间,对他进行格式转换
System.out.println(new SimpleDateFormat("HH:mm:ss").format(starTime));
starTime = new Date(System.currentTimeMillis());//更新当前时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//模拟倒计时
public static void tenDown() throws InterruptedException {
int num = 10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if (num<=0){
break;
}
}
}
}