多线程编程

多线程

进程

在计算机中,我们把一个任务称为一个进程,浏览器就是一个进程,视频播放器是另一个进程,类似的,音乐播放器和Word都是进程。

某些进程内部还需要同时执行多个子任务。例如,我们在使用Word时,Word可以让我们一边打字,一边进行拼写检查,同时还可以在后台进行打印,我们把子任务称为线程

每一个进程都是有程序代码组成的,这些代码在进程中 有CPU轮流进行执行

操作系统调度的最小任务单位其实不是进程,而是线程。

因为同一个应用程序,既可以有多个进程,也可以有多个线程

同一个应用程序,既可以有多个进程也可以有多个线程

  • 多进程模式(每个进程有一个线程)
  • 多线程模式(一个进程有多个线程)
  • 多进程+多线程(复杂度最高)

线程

线程是进程中的一个执行单元/执行路径,负责当前进程中程序的执行

一个进程中至少要有线程,也可存在多个线程的,这种程序我们称之为多线程程序

进程和线程是包含关系,但是多任务既可以由多进程实现,也可以由单进程内的多线程实现,还可以混合多进程+多线程。

具体采用哪种方式,要考虑到进程和线程的特点。

和多线程相比,多进程的缺点在于:

  • 创建进程比创建线程开销大,尤其是在Windows系统上;
  • 进程间通信比线程间通信要慢,因为线程间通信就是读写同一个变量,速度很快。

而多进程的优点在于:

多进程稳定性比多线程高,因为在多进程的情况下,一个进程崩溃不会影响其他进程,而在多线程的情况下,任何一个线程崩溃会直接导致整个进程崩溃。

和单线程相比,多线程编程的特点在于:多线程经常需要读写共享数据,并且需要同步。

多线程编程的复杂度高,调试更困难。

创建多线程

实现多线程有两种方式 继承Thread类和实现Runnable接口

要创建一个新线程,我们需要实例化一个Thread实例,然后调用它的start()方法

继承Thread

Thread派生一个自定义类,然后覆写run()方法

一个类继承了Thread类的话 就具备了可以被多线程执行的功能

继承Thread 相当于与获得了一个 执行路径
还差一个 执行任务 重写run函数
run函数不是由我们调用的 由JVM调用
start开辟一个执行路径 由虚拟机具体执行 run

具体步骤:

​ (1)定义一个类继承Thread
​ (2)重写run函数
​ (3)创建子类对象,就是创建线程对象
​ (4)调用start方法,开启线程并让线程执行,同时告诉JVM去调用run方法

public class Main {
    public static void main(String[] args) {
        Demo d1 = new Demo("小红");
        Demo d2 = new Demo("小明");
        System.out.println(d1.getName());   //Thread-0 小红
        System.out.println(d2.getName());   //Thread-1 小明

        d1.start();
        d2.start();
        for (int i = 1; i <= 50; i++) {
            System.out.println(Thread.currentThread().getName() + i);
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //return
    }
}

class Demo extends Thread {
    public Demo(String name) {
        super(name);    //-> Thread() -> "Thread-" + num
    }
    public void show() {
        for (int i = 1; i <= 50; i++) {
            System.out.println(getName());  //当前线程对象的名称
            //当前代码所在线程对象的名称
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
    //run函数描述的就是当前线程需要被执行的任务
    @Override
    public void run() {
        for (int i = 1; i <= 50; i++) {
            System.out.println(Thread.currentThread().getName() + i);
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //一个线程运行的过程中个如果出现异常 则不会影响其他线程的执行!
            
            if (getName().equals("小明") && i == 30) {
                throw new NullPointerException();
            }
        }
    }
}

start()方法会在内部自动调用实例的run()方法。

实现Runnable接口

创建Thread实例时,传入一个Runnable实例

如果某一个类已经继承了别的类 则不能在重新继承Thread

(1)定义类实现Runnable接口 创建一个任务类
(2)重写run函数 就是任务的具体执行内容
(3)外面创建Thread对象 创建执行路径
(4)任务对象与Thread对象进行关联:将Runnable接口的子类对象作为参数传递给Thread的构造函数
(5)调用start()

public class Main {
    public static void main(String[] args) {
        PrintNumberTask r1 = new PrintNumberTask();
        Thread t1 = new Thread(r1);

        PrintNumberTask r2 = new PrintNumberTask();
        Thread t2 = new Thread(r2);

        Thread t3 = new Thread(()->{
            for (int i = 1; i <= 20; i++) {
                System.out.println(Thread.currentThread().getName() + "-" + i);
            }
        });

        t1.start();
        t2.start();
        t3.start();
    }
}
class PrintNumberTask implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + "-" + i);
        }
    }
}

用Java8引入的lambda语法进一步简写为:

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start(); // 启动新线程
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("start new thread!");
    }
}

要模拟并发执行的效果,我们可以在线程中调用Thread.sleep(),强迫当前线程暂停一段时间

用多线程的技术去复制目录中指定文件

import java.io.*;

//用多线程的技术去复制目录中指定文件
public class Main {
    public static void main(String[] args) {
        //创建文件对象
        File source = new File("C:\\Users\\jameth\\Desktop\\aab\\JavaSE");
        File aim = new File("C:\\Users\\jameth\\Desktop\\Code");
        //判断路径是否存在
        if (!aim.exists()) {
            aim.mkdir();
        }
        //拷贝文件
        traversal(source, aim);
    }

    private static void traversal(File dir, File aimdir) {
        File[] files = dir.listFiles();
        if (files != null && files.length != 0) {
            for (File file : files) {
                if (file.isFile()) {
                    if (file.getName().endsWith(".java")) {
                        //创建执行任务对象
                        CopyFileTask task = new CopyFileTask(file, new File(aimdir, file.getName()));
                        //创建执行道路 并且关联执行任务
                        Thread thread = new Thread(task);
                        thread.start();

                    }
                } else {
                    traversal(file, aimdir);
                }
            }
        }
    }
}

class CopyFileTask implements Runnable {
    private File source;
    private File aim;

    public CopyFileTask(File source, File aim) {
        this.source = source;
        this.aim = aim;
    }

    @Override
    public void run() {
        BufferedInputStream bis = null;
        FileInputStream fis = null;
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(source);
            fos = new FileOutputStream(aim);
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            byte[] buf = new byte[1024 * 1024];
            int len = 0;
            while ((len = bis.read(buf)) != -1) {
                bos.write(buf, 0, len);
                bos.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(source.getName() + "拷贝完成!");
    }
}

Java用Thread对象表示一个线程,通过调用start()启动一个新线程;

一个线程对象只能调用一次start()方法;

线程的执行代码写在run()方法中;

线程调度由操作系统决定,程序本身无法决定调度顺序;

Thread.sleep()可以把当前线程暂停一段时间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
多线程 求质数 返回数组中的最大值 bool isPrime(long x) { if (x <= 1) return false; if (x == 2) return true; for (long i = 2; i <= ceil(sqrt((long double)x));i++) if (x%i == 0) return false; return true; } DWORD WINAPI findPrime(void* p) { long result=0; int l = stc(p)->lower, u = stc(p)->uper; int t_id=GetCurrentThreadId(); for (int i = l; i <= u;i++) if (isPrime(i)) { result++; } DWORD dReturn = WaitForSingleObject(mutex_mul_result_h, INFINITE); mul_result += result; ReleaseMutex(mutex_mul_result_h); //EnterCriticalSection(&gCRITICAL_SECTION_Printf); //printf("%d,%d,%d,%d\n", l, u, result,t_id); //fflush(stdout); //LeaveCriticalSection(&gCRITICAL_SECTION_Printf); return 0; } //dispatcher void dispatch() { DWORD Status; timer tm; tm.start(); //srand(time(NULL)); long step = STEP;//ceil(double(TEST/10)); handlenum = 0; for (int i = 1; i <= TEST;) { i += step; handlenum++; } handle_array=new HANDLE[handlenum]; Thread_id = new DWORD[handlenum ]; arg = new FP_ARG[handlenum]; InitializeCriticalSection(&gCRITICAL_SECTION_Printf); mutex_mul_result_h = CreateMutex(NULL, false, mutex_mul_result); handlenum = 0; for (int i = 1; i <= TEST;) { arg[handlenum].lower = i; arg[handlenum].uper = (i + step-1>TEST) ? TEST : i + step-1; handle_array[handlenum]=(HANDLE)CreateThread(NULL, 0, findPrime, &arg[handlenum], 0, &Thread_id[handlenum]); /*EnterCriticalSection(&gCRITICAL_SECTION_Printf); printf("lower:%d uper:%d thread_id:%d\n", arg[handlenum].lower, arg[handlenum].uper,Thread_id[handlenum]); LeaveCriticalSection(&gCRITICAL_SECTION_Printf);*/ i += step; handlenum++; } tm.stop(); Sleep(1000); printf("there are %d threads\n", handlenum); printf("the multithreads use %f msc\n", tm.read()); } //the number of 1-1000000 Primenumber void s_finePrime() { timer tm; long result = 0; tm.start(); for (int i = 1; i <= TEST; i++) if (isPrime(i)) result++; tm.stop(); printf("Single thread result is %d\n", result); printf("Single thread use %f msc\n", tm.read()); } int _tmain(int argc, _TCHAR* argv[]) { dispatch(); WaitForMultipleObjects(handlenum, handle_array, true, INFINITE);//不起作用 printf("the multithreads reslut is %d\n", mul_result); CloseHandle(mutex_mul_result_h); DeleteCriticalSection(&gCRITICAL_SECTION_Printf); s_finePrime(); system("pause"); return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_59138290

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值