多线程(二)

1.创建线程

2.中断线程

让线程结束(就是让内核中的pcb销毁)其关键就是让线程对应的入口方法,执行完毕
其中,入口方法指的就是:
继承thread重写的run,实现runnable重写的run,lambda.只要run执行完毕,线程就随之结束,更多的情况,线程不一定这么快就执行完run
例如:
在这里插入图片描述

实际,我们并不希望run就是一个死循环,更希望能过控制这个线程,按照我们的需要随时结束;
为了实现这个效果:

  1. 用boolean变量来作为循环结束标志
  2. 刚才是使用自己定义的变量来作为循环标记,还可以使用标准库中内置的标记

获取线程内置的标志位:线程的isInterrupted()判断当前线程是不是应该要结束循环

修改线程内置的标记位:Thread.interrupt()来修改这个标记位
在这里插入图片描述

当3s之后;
interrupt方法貌似没有修改这个标记位,循环看起来还是在执行,
同时这里有个异常
在这里插入图片描述

这里的interrupt方法可能会有两种行为:

当前线程正在运行中,此处会修改Thread.currentThread().isInterrupted()标记为true;
如果当前线程正在sleep/wait/等待锁,,,此时会触发InterrutedException

在这里插入图片描述

isInterrupted()这个是Thread的实例方法
和这个方法类似的:
interrupted()这个是Thread的类方法(static)
public void interrupt()
中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,
否则设置标志位
public static boolean interrupted()
判断当前线程的中断标志位是否设置,调用后清除标志位
//开关按下去 会自动弹回来
public boolean isInterrupted()
判断对象关联的线程的标志位是否设置,调用后不清除标志位
//开关按下去,不会自动弹回来
实际上,这两者有区别,使用静态的,会自动清除标记位,使用非静态的不会对标记位进行清除


thread 收到通知的方式有两种:

  1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通
    知,清除中断标志
    当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择
    忽略这个异常, 也可以跳出循环结束线程.
  2. 否则,只是内部的一个中断标志被设置,thread 可以通过
    Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
    Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志
    这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到。

缘由
  很多人认为多线程中的Thread.currentThread()和this都是显示当前线程的意思,其实不然,他们两个代表不同的意思,下面用一个小例子说明一下。

package currentThreadAndThis;
public class MyThread extends Thread {
    public MyThread(){
        System.out.println("当前线程的名字:"+Thread.currentThread().getName());
        System.out.println("当前线程的名字:"+this.getName());
    }
    @Override
    public void run(){
        System.out.println("当前线程的名字:"+Thread.currentThread().getName()+"   run=="+Thread.currentThread().isAlive());
        System.out.println("当前线程的名字:"+this.getName()+"  run=="+this.isAlive());
    }
}

//启动类
package currentThreadAndThis;
public class Run {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        //初始化Thread对象,方便调用start();
        //此时myThread作为参数传入Thread中,其实是myThread委托thread去执行;
        Thread thread=new Thread(myThread);
        //初始化自定义线程名称
        thread.setName("C");
        //启动线程
        thread.start();

    }
}

运行结果
1.当前线程的名字:main
2.当前线程的名字:Thread-0
3.当前线程的名字:C run == true
4.当前线程的名字:Thread-0 run ==false

然后我们会看到执行构造函数 MyThread myThread=new MyThread();,然后打印的结果是“当前线程的名字:main ;当前线程的名字:Thread-0”.
为什么会是这样呢?来分析一下源码:

分析
(一)首先看一下首先看Thread.currentThread方法源码:
在这里插入图片描述
 它返回的是当前执行的线程;然后我们首先启动的是main线程,所以我们打印出------- “当前线程的名字:main”

(二)来看一下,this的调用,首先分析一下Thread的构造函数:
在这里插入图片描述

线程在初始化对象的时候, this代表的当前对象MyThread,然后Thread在初始化对象的时候,会给线程起一个默认的初始名,所以this.getname()打印出来是“当前线程的名字:Thread-0”。
 (1) 在执行“ thread.start();”时,因为myThread作为参数传入Thread中,其实是myThread委托thread去执行;所以在执行–“ thread.setName(“C”);”,通过“Thread.currentThread().getName()”打印出来时“当前线程的名字:C”。
 (2) 但是此时执行this.getname()仍然代表的是Mythread这个对象,所以打印出来的仍然是“当前线程的名字:Thread-0”
结论
①Thread.currentThread表示当前代码段正在被哪个线程调用的相关信息。
②this表示的是当前对象,与Thread.currentThread有很大的区别。

3 线程等待

线程与线程之间,调度顺序是完全不确定的(取决于操作系统调度器自身的实现)

而但是有时候 希望顺序可控制
此时线程等待是一个方法
这里的线程等待,主要就是控制线程结束的先后顺序

一种常见的逻辑:t1线程,创见t2,t3,t4这三个新的线程来执行一些任务,然后t1线程最后在这里汇总结果
这种场景就需要t1的结束时机必须比t2,t3,t4都迟

Thread t=new Thread();
t.join();//执行到这个代码,调用这个代码的线程就会阻塞等待,代码不继续往下走了,具体来说就是操作系统短时间内不会把这个线程调度到cpu上面了
之前有阻塞等待的代码:
Scanner scanner =new Scannner(System.in);
scanner.nextInt();//尝试从键盘中读入一个数据-》用户输入的 此时触发阻塞等待

public class Test5 {
    public static void main(String[] args) {
        //创建两个线程t1,t2
        Thread t1=new Thread(){
            @Override
            public void run() {
                int count=0;
                while(count<5){
                    count++;
                    System.out.println("程序运行中");
                    try{
                        Thread.sleep(1000);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
                System.out.println("程序运行结束");
            }

        };
        //执行start方法的时候,会立刻创建出一个新的线程来,
        //同时main这个线程也会立刻往下进行,直到执行到t1.join();
        //执行到t1.join()的时候发现,此时t1线程正在运行
        //只要t1在运行中,join方法就会一直阻塞等待,一直等到t1的run执行结束
        t1.start();
        try{
            //当t1执行完了,再调用join会出现什么,此时不会阻塞等待,直接运行了
            Thread.sleep(7000);
            //此时的join就会阻塞等待
            System.out.println(Thread.currentThread().getName()+"join执行开始");
            t1.join();
            System.out.println("join执行结束");
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}

public void join() 等待线程结束,死等,往往比较危险,典型是网络编程中,发了一个请求,希望得到一个回应,但是由于种种原因,回应没有到达,会一直等待
public void join(long millis) 等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos) 同理,但可以更高精度,纳秒等待

CurrentThread可以获取当前Thread线程实例的引用

public class Test6 {
    public static void main(String[] args) {
        Thread t=new Thread(){
            @Override
            public void run(){
                System.out.println(Thread.currentThread().getId());//22
                System.out.println(this.getId());//22
            }

        };
        //在这个代码中,得到的就是t这个引用,相当与在run中直接使用this;
        t.start();

    }
}

public static void sleep(long millis) throws InterruptedException
休眠当前线程 millis
public static void sleep(long millis, int nanos) throws InterruptedException
可以更高精度的休眠

sleep这个方法,本质上是把线程PCB从就绪队列,移动到了阻塞队列

操作系统管理线程:

  1. 描述:PCB;
  2. 组织:双向链表(其实不仅仅是以一个)

4.线程的状态

用于辅助 系统对于线程进行调度的属性

线程的状态是用一个枚举类型Thread.State

public class Test7 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(){
            @Override
            public void run(){
                while(!Thread.currentThread().isInterrupted()){
                    System.out.println("线程正在运行中");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
                System.out.println("线程已经结束");
            }

        };
        //NEW:Thread对象创建出来了,但是内核中的PCB还没有创建出来
        //RUNNABLE:当前的PCB也创建出来了,同时这个PCB随时待命(就绪),这个线程可能是正在cPU上运行,可能就是在就绪队列中排队
        //TIMED_WAITING:表示当前的PCB在阻塞队列中等待,这个等待是带有“结束时间”的等待
        //TERMINATED:表示当前的PCB已经结束了,Thread对象还在,此时调用获取状态,得到的就是这状态
        System.out.println(t.getId()+":"+t.getState());//NEW
        t.start();
        System.out.println(t.getId()+":"+t.getState());//RUNNABLE
        try {
            System.out.println("当线程在cpu上运行,第一次等待三秒");
            Thread.sleep(3000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        //改变状态,该为false run结束
        t.interrupt();

        try {
            System.out.println("此时线程结束,第二次等待三秒,不会再等待3秒,直接结束");
            Thread.sleep(3000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        //TERMINATED:表示当前的PCB已经结束了,Thread对象还在,此时调用获取状态,得到的就是这状态
        System.out.println(t.getId()+":"+t.getState());

    }
}
//22:NEW
//线程正在运行中
//22:RUNNABLE
//当线程在cpu上运行,第一次等待三秒
//线程正在运行中
//线程正在运行中
//此时线程结束,第二次等待三秒,不会再等待3秒,直接结束
//线程已经结束
//java.lang.InterruptedException: sleep interrupted
// at java.base/java.lang.Thread.sleep(Native Method)
// at Test7$1.run(Test7.java:16)
//22:TERMINATED

NEW:Thread对象创建出来了,但是内核中的PCB还没有创建出来
RUNNABLE:当前的PCB也创建出来了,同时这个PCB随时待命(就绪),这个线程可能是正在cPU上运行,可能就是在就绪队列中排队

TIMED_WAITING:表示当前的PCB在阻塞队列中等待,这个等待是带有“结束时间”的等待
WAITING:线程中如果调用了wait方法,也会阻塞等待,此时处在WAITING状态(死等)除非其他线程唤醒了此线程
BLOCKED:线程中尝试进行加锁,结果发现锁已经被其他线程占用,此时该线程也会阻塞等待,这个等待会在其他线程释放锁之后,被唤醒

此三种都表示阻塞等待,结束阻塞等待的条件不一样

TERMINATED:表示当前的PCB已经结束了,Thread对象还在,此时调用获取状态,得到的就是这状态

在这里插入图片描述
在这里插入图片描述

当前这几个状态,就是Java中的Thread类中的状态,他与操作系统中的pcb中的状态不一样
yield() 让线程主动让出cpu,不会改变线程的状态

  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于您没有给出具体的问题或数据集,我无法为您提供完整的代码,但我可以给您提供一些思路和伪代码来实现多线程维卷积计算。 1. 定义卷积核和输入图像 ``` kernel = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]] # 3x3 Sobel filter image = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] # 4x4 input image ``` 2. 定义卷积函数 ``` def convolve(kernel, image): # Get kernel and image dimensions kernel_height, kernel_width = len(kernel), len(kernel[0]) image_height, image_width = len(image), len(image[0]) # Initialize output image output = [[0 for _ in range(image_width - kernel_width + 1)] for _ in range(image_height - kernel_height + 1)] # Compute convolution for i in range(kernel_height): for j in range(kernel_width): for k in range(image_height - kernel_height + 1): for l in range(image_width - kernel_width + 1): output[k][l] += kernel[i][j] * image[k+i][l+j] return output ``` 这个函数实现了基本的维卷积计算,但是它是串行的。我们需要将其并行化以加快计算速度。 3. 定义多线程卷积函数 ``` import threading class ConvolutionThread(threading.Thread): def __init__(self, kernel, image, output, row_start, row_end): threading.Thread.__init__(self) self.kernel = kernel self.image = image self.output = output self.row_start = row_start self.row_end = row_end def run(self): # Get kernel and image dimensions kernel_height, kernel_width = len(self.kernel), len(self.kernel[0]) image_height, image_width = len(self.image), len(self.image[0]) # Compute convolution for i in range(kernel_height): for j in range(kernel_width): for k in range(self.row_start, self.row_end): for l in range(image_width - kernel_width + 1): self.output[k][l] += self.kernel[i][j] * self.image[k+i][l+j] def parallel_convolve(kernel, image, num_threads): # Get kernel and image dimensions kernel_height, kernel_width = len(kernel), len(kernel[0]) image_height, image_width = len(image), len(image[0]) # Initialize output image output = [[0 for _ in range(image_width - kernel_width + 1)] for _ in range(image_height - kernel_height + 1)] # Split image into rows for each thread rows_per_thread = (image_height - kernel_height + 1) // num_threads threads = [] for i in range(num_threads): row_start = i * rows_per_thread row_end = row_start + rows_per_thread if i == num_threads - 1: row_end = image_height - kernel_height + 1 thread = ConvolutionThread(kernel, image, output, row_start, row_end) threads.append(thread) # Start threads for thread in threads: thread.start() # Wait for threads to finish for thread in threads: thread.join() return output ``` 这个函数将输入图像分成多个线程处理。每个线程处理一组连续的行。将图像分成多个线程可以大大减少计算时间。 4. 调用多线程函数 ``` num_threads = 4 result = parallel_convolve(kernel, image, num_threads) ``` 这个例子中,我们将输入图像分成4个线程处理。您可以根据计算机的处理器核心数量来选择线程数,以达到最佳性能。 希望这些思路和伪代码能够帮助您实现多线程维卷积计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值