文章目录
一、并发VS并行
- 并发(concurrent)是同一时间应对(dealing with)多件事情的能力。并发是在同一实体上的多个事件,多个事件在同一时间间隔发生
- 并行(parallel)是同一时间动手做(doing)多件事情的能力
二、进程VS线程
- 进程:是系统进行资源分配和调度的基本单位(操作系统分配的资源和调度对象其实是CPU时间片)
- 线程:是操作系统能够进行资源调度的最小单位,它被包含在进程中,是进程中实际运行单位。
进程是资源分配的最小单位。线程是程序执行的最小单位(线程是操作系统能够进行资源调度的最小单位,同一个进程中的线程也可以被同时调度到多个CPU上运行),线程也被称为轻量级进程。
内存共享:默认情况下,进程的内存无法与其他进程共享(进程间通信通过IPC进行)。线程共享由操作系统分配给其父进程的内存块。
三、多线程实现方式之继承Thread类
使用说明:1.重写Thread类中的run()方法,2.使用start()方法启动线程
注意:每次创建一个新的线程,都要新建一个Thread子类的对象
代码如下(示例):
/**
* Java实现多线程的方式1
* 继承Thread类,重写run方法
*/
class MyThread extends Thread {//线程主体类
@Override
public void run() {
//这里可以写thread执行的任务内容
System.out.println(Thread.currentThread().getName());
}
}
public class demo1 {
public static void main(String[] args) {
for(int i=0;i<2;i++) {
Thread t = new MyThread();
t.start(); //调用Thread的start()方法启动线程
}
}
}
运行结果如下(示例):
四、多线程实现方式之实现Runnable接口
使用说明:1.重写run()方法,2.使用new Thread(Runnable接口实现类的对象).start()方法启动线程
注意:不论创建多少个线程,只需要创建一个Runnable接口实现类的对象
代码如下(示例):
class ImplRunnable implements Runnable{
private volatile int i = 0;
@Override
public void run() {
//这里可以写thread执行的任务内容
System.out.println(Thread.currentThread().getName()+"--"+ i++);
}
}
public class demo2 {
public static void main(String ards[]){
Runnable implRunnable = new ImplRunnable();
for(int i=0;i<5;i++){
new Thread(implRunnable).start();
}
}
}
运行结果:
五、多线程实现方式之实现 Callable接口
前面两种创建方式都是复写 run 方法,都是 void 形式的,没有返回值。但是对于方式三来说,实现 Callable 接口,能够有返回值类型。
使用说明:1:实现 Callable 接口,implements Callable; 2:复写 call () 方法,call () 方法是线程具体逻辑的实现方法。
public class ImplCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "创建线程通过实现Callable接口";
}
}
public class ImplCallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> future1 = new FutureTask<String>(new ImplCallable());
Thread thread1 = new Thread(future1,"t1");
thread1.start();
System.out.println(future1.get());
}
}
六、多线程join方法
说明:多线程环境下,如果需要确保某一线程执行完毕后才可继续执行后续的代码,就可以通过使用 join 方法完成这一需求设计
场景举例:
线程 1 :执行时间 5 秒钟;
线程 2 :执行时间 10 秒钟;
线程 3 :执行 8 秒钟。
需求:我们需要等 3 个线程都执行完毕后,再进行后续代码的执行。3 个线程执行完毕后,打印执行时间。
public class JoinDemo {
public static void main(String[] args) {
//线程1
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1休眠5秒钟,执行完毕!");
}
});
//线程2
ImplRunnable implRunnable = new ImplRunnable();
Thread thread2 = new Thread(implRunnable);
//线程3
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程3休眠8秒钟,执行完毕!");
}
});
long startTime = System.currentTimeMillis();
thread1.start();
thread2.start();
thread3.start();
//jion方法
try{
thread1.join();
thread2.join();
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("三个线程全部执行完毕,共用时: "+(endTime-startTime)+"毫秒");
}
}
补充:
join() //无参,线程全部执行完毕
join(long millis) //有参,等待 millis 毫秒终止线程,假如这段时间内该线程还没执行完,也不会再继续等待。
六、多线程yield方法
当一个线程调用 yield 方法时,实际就是在暗示线程调度器当前线程请求让出自己的 CPU 使用权。
- 作用
暂停当前正在执行的线程对象(及放弃当前拥有的 cup 资源),并执行其他线程。yield () 做的是让当前运行线程回到就绪状态,以允许具有相同优先级的其他线程获得运行机会。 - 目的:
yield 即 “谦让”,使用 yield () 的目的是让具有相同优先级的线程之间能适当的轮转执行。
但是,实际中无法保证 yield () 达到谦让目的,因为放弃 CPU 执行权的线程还有可能被线程调度程序再次选中。
例子:
创建一个线程,线程名为 threadOne;
打印一个数,该数的值为从 1 加到 10000000 的和;
不使用 yield 方法正常执行,记录总的执行时间;
加入 yield 方法,再次执行程序;
再次记录总执行时间。
期望结果:
未加入 yield 方法之前打印的时间 < 加入 yield 方法之后的打印时间。
因为 yield 方法在执行过程中会放弃 CPU 执行权并从新获取新的 CPU 执行权。
public class YieldDemo {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
long startTime = System.currentTimeMillis();
int count = 0;
for (int i = 1; i < 100000; i++) {
count += i;
}
long endtime = System.currentTimeMillis();
System.out.println("总执行时间: " + (endtime - startTime) + " 毫秒, 结果 count = " + count);
}
});
thread1.start();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
long startTime = System.currentTimeMillis();
int count = 0;
for (int i = 1; i < 100000; i++) {
count += i;
Thread.yield();
}
long endtime = System.currentTimeMillis();
System.out.println("总执行时间: " + (endtime - startTime) + " 毫秒, 结果 count = " + count);
}
});
thread.start();
}
}
七、 yield() VS sleep()
- sleep()方法给其他线程运行机会时不考虑现场的优先级,因此会给低优先级的线程以运行的机会;
- yield()方法只会给相同优先级或更高优先级的线程以运行机会;
- 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
- sleep()方法声明会抛出InterruptedException,而yield()方法没有声明任何异常;
- sleep()方法比yield()方法具有更好的移植性(跟操作系统CPU调度相关);
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/119833.html