java 多线程并行_Java线程与并行编程(一)

你好,我是goldsunC

让我们一起进步吧!

进程与线程

进程是程序的一次动态执行过程,它对应从代码加载、执行到执行完毕的一个完整过程。这个过程也是进程本身从产生、发展到消亡的过程,同一段程序,可以被多次的加载到系统中的不同内存区域分别执行,从而形成不同的进程。

线程是比进程更小的执行单位,一个进程在执行过程中可以产生多个线程。每个线程都有它自己的产生、存在和消亡过程。当你开启一个新的进程时,系统都会给进程分发一块专用的内存区域,并以PCB(进程控制块)作为它的标志。而线程间可以共享相同的内存,并可以利用这些共享单元来实现数据交换、实时通信与必要的同步操作。

线程

一个线程应该包括三个部分:代码、数据以及CPU。CPU:虚拟的CPU,用于执行该线程的任务。

代码:即线程中需要执行的指令,在程序中表现为特定的方法。

数据:即线程中要处理的数据,在程序中表现为各变量。

在Java中,由java.lang.Thread类来实现线程。

为了构造Thread类对象,可以像Thread的构造函数中传递一个Runnable对象,这个对象是线程所需要的代码和数据的封装。

这个Runnable对象是指任何实现了java.lang.Runable接口的对象,Runnable接口只有一个方法public void run(),这个方法里面应包含线程需要执行的代码。

如果要启动线程中的代码,只需要执行Thread类的start()方法即可,系统会自动取执行run()方法中规定的代码。

创建线程的两种方法

继承Thread

你可以从Thread派生出一个新的类,可以在其中加入需要的属性和方法,同时需要覆盖run()方法,不需要重写start()方法,当你创建好这样一个对象后,调用start()方法即可启动该线程。

需要注意的是,虽然run()方法包含了线程要执行的指令,但是我们一般不直接调用它,而是调用start()来启动线程。

如下一个示例:

public class Thread1 {

public static void main(String[] args) {

MyThread1 th1 = new MyThread1();

MyThread1 th2 = new MyThread1();

th1.start();

th2.start();

}

}

class MyThread1 extends Thread {

public void run() {

for (int i=0; i<10; i++)

System.out.print(" "+i);

}

}

OUT:

0 1 0 1 2 3 4 5 6 7 2 8 3 9 4 5 6 7 8 9

该示例通过继承Thread类定义了自己线程类,然后用new创建了两个线程对象并启动。可以看到输出为两个线程同时执行的结果。

向Thread传递Runnable对象

如下一个示例:

public class Thread2 {

public static void main(String[] args) {

MyJob job1 = new MyJob(20);

MyJob job2 = new MyJob(20);

Thread thread1 = new Thread(job1);

Thread thread2 = new Thread(job2);

thread1.start();

thread2.start();

}

}

class MyJob implements Runnable {

private int num;

public MyJob(int num) {

this.num = num;

}

@Override

public void run() {

for (int i=0; i

System.out.print(" "+i);

}

}

OUT:

0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 11 10 12 11 13 12 13 14 14 15 15 16 16 17 17 18 18 19 19

如上程序首先定义了一个MyJob类,它实现了Runnable接口,重写了run()方法。在创建线程时先创建了两个MyJob对象,然后向Thread构造函数中传入该对象,即可使用start()方法启动线程。

上面两种方法都可以创建线程,但是实现方式略有不同,当然也有相同的地方,接下来我们对比分析一下两者的不同及特点。继承Thread:直接继承Thread的话,实现起来简单一些,可以直接操纵线程,但是如果你继承了Thread类,就不能再从其他类继承。

实现Runnable接口:这种方法实现起来稍微麻烦一点,但是可以将Thread类与要处理任务的类分离开,我们定义专门的任务类,可以形成比较清晰的模型。同时实现此接口的同时可以继承其他类。

需要注意的是,如果直接继承Thread类,那么在类中this即指当前的线程对象,而使用Runnable接口的话,需要在类中使用Thread.currentThread()方法来获得当前的线程。

使用匿名类及Lambda表达式

在创建线程时,还可以实现匿名类!而且因为Runnable接口是函数式接口,所以可以写成Lambda表达式!还记得函数式接口是什么吗?它就是只含有一个抽象方法的接口。这个很重要哦。

如下一个示例:

public class Thread3 {

public static void main(String[] args) {

new Thread() {

public void run() {

for (int i=0;i<20;i++)

System.out.print(" "+i);

}

}.start();

new Thread(()->{

for (int i=0;i<20;i++)

System.out.print(" "+i);

}).start();

}

}

OUT:

0 1 2 3 4 5 6 7 8 9 10 11 12 0 13 1 14 2 15 3 16 4 17 5 18 6 19 7 8 9 10 11 12 13 14 15 16 17 18 19

如上示例中分别用了匿名类和Lambda表达式创建了两个线程。

Timer类

程序中,有一些任务需要隔一定的实际重复执行,实现这样的任务可以使用Timer类。

Timer类的常用构造方法如下:

Timer timer = new Timer("名字");

Timer类可以用以下方法来实现任务的调度:

schedule(TimerTask task, long delay, long period);

其中,TimerTask是表示所要重复执行的任务,在实际使用时要继承抽象类TimerTask并实现其中的run方法,delay表示第一次执行前要等待的时间(毫秒),period是没两次执行的时间间隔(毫秒)。

如下一个示例:

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

public class TimerTest {

public static void main(String[] args) {

Timer timer = new Timer("goldsunC");

TimerTask task = new MyTask();

timer.schedule(task,1000,1000);

}

}

class MyTask extends TimerTask {

int n = 0;

public void run() {

n++;

System.out.print(new Date());

System.out.println("---"+n);

}

}

这个实例会在屏幕上每隔1秒打印一次当前时间,用到了Timer及schedule方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值