进程和线程的概念
进程:一个具有独立内存空间的执行程序
线程:是进程中的其中一条执行路径(多条就是多线程),每个进程最少有一个进程 同一个进程中的多个线程共享同一个内存空间
我们Windows中任务管理器中的就是进程
线程, 如图所示, 在进程中可能包含多个线程,也可以说是多条执行路径, 每个线程之间还可能会有交叉(数据的沟通)
网上有个典型的例子可以跟大家分享一下:
进程与线程的一个简单解释
实现多线程的两种方式
1,继承Thread类
2,实现Runable接口(推荐使用)
接下类针对两种方法进行详细阐述:
继承Thread类方法:
步骤: 1, 当然是继承Thread类 2, 重写run()方法
// 继承Thread类实现线程
static class MyThread extends Thread {
@Override
public void run() {
// 在此方法中编写线程要执行的工作
}
}
实现Runable接口(推荐使用):
步骤: 1, 实现Runable方法 2, 同样重写run() 方法
推荐原因: 由于Java不支持继承多个父类,但是可以实现多个接口, 如果直接继承Thread类, 在后续开发过程中就没有继承其他类的机会了!所以推荐使用实现Runnable接口
// 实现Runable接口的方式实现线程 推荐使用
static class MyRunnable implements Runnable {
@Override
public void run() {
// 在此方法中编写线程要执行的工作
}
}
常用的几个操作方法
- Thread(Runnable target) 分配新的 Thread 对象。这种构造方法与 Thread(null, target,gname) 具有相同的作用,其中的 gname 是一个新生成的名称。自动生成的名称的形式为 “Thread-”+n,其中的 n 为整数。
- start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。 - getId() 返回该线程的标识符。
- getName() ,setName(String name) 线程名称的get和set方法
- getPriority() ,setPriority(int newPriority) 优先级的get和set方法
- currentThread() 返回对当前正在执行的线程对象的引用。
- isAlive() 测试线程是否处于活动状态。
- join(), join(long millis) 等待该线程终止。
- yield() 暂停当前正在执行的线程对象,并执行其他线程。
setDaemon(boolean on) 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。
sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。也就是说线程执行sleep方法时不会让出自己锁, 要注意和Object中wait() 方法差异,在后面会有阐述
以上部分方法的示例代码如下:
package com.lulu;
public class ThreadDemo1 {
public static void main(String[] args) {
// 分配新的 Thread 对象。
Thread t1 = new Thread(new MyRunnable());
System.out.println("isAlive-->" + t1.isAlive());
// 启动该线程
t1.start();// 线程已准备就绪(就绪状态)等待CPU的调度
System.out.println("isAlive-->" + t1.isAlive());
// 很少用到getId()方法
System.out.println("Id-->" + t1.getId());
System.out.println("Name-->" + t1.getName());
// 设置抢占CPU执行时间的优先级
// t.setPriority(Thread.MAX_PRIORITY);// 只是几率大但不保证每次抢占成功
MyThread t2 = new MyThread();
t2.start();
// 使用Main方法中的线程演示Join方法
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Thread.currentThread():返回对当前正在执行的线程对象的引用。
System.out.println(Thread.currentThread().getName() + "->" + i);
if (i == 2) {
try {
// 此处的含义是, 当i==2时等待t1执行完再执行自己的线程
t1.join();
// 如果t1线程异常中断了,会抛出下面的异常
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
static class MyThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
for (int i = 0; i < 5; i++) {
try {
// Causes the currently executing thread to sleep
// (temporarily cease execution) for the specified number of
// milliseconds, subject to the precision and accuracy of
// system timers and schedulers. The thread does not lose
// ownership of any monitors.
// 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),
// 此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Thread.currentThread():返回对当前正在执行的线程对象的引用。
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}
static class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Thread.currentThread():返回对当前正在执行的线程对象的引用。
System.out.println(Thread.currentThread().getName() + "->" + i);
}
}
}
}
程序运行结果:
对于线程各方法的执行过程可以参考下图:
上图中部分方法会在后续博客中给出说明.
未完待续….
以上纯属个人见解, 如有不足之处希望有高人指出, 定感激不尽, 如有喜欢交流学习经验请给我留言谢谢.
原创文章, 转载请注明出处