进程与线程

进程: 指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程.

线程: 指进程中的一个执行任务(控制单元),是程序执行时的最小单位,是CPU调度和分派的基本单位,一个进程可以运行多个线程,多个线程可共享资源.

并行与并发

并行: 多个进程同时运行,发生在多CPU中,一个进程占一个CPU,所有进程同步运行,互相之间不抢夺资源

并发: 多个进程间隔运行,发生在单CPU中,每个进程切换运行,切换时间很短,所以看起来好像是同时在运行,互相之间抢夺资源

同步与异步

同步: 多个线程有序执行,前面的执行完了后面的补上,在前面线程运行时其他线程都在等待

异步: 多个线程同时进入就绪状态,等待CPU的统一调度,当线程进入运行状态时其他线程可以访问其他资源,把访问资源的空闲时间利用起来,能提高效率,也就是多线程机制

线程分类

应用线程: 前台线程,执行各种具体任务的线程,一个程序启动至少有一个应用线程(main线程)和一个守护线程(GC)

守护线程: 后台线程,随着前台线程的全部死亡,守护线程也会自动死亡

线程的创建和启动

继承方式创建

自定义类继承Thread

重写run方法,把线程任务封装进run方法中

创建自定义对象

自定义对象调用start()方法,开启线程

// 继承方式创建线程

public class MyThreadDemo extends Thread { // 继承Thread类创建线程

// 重写run方法,把线程任务封装进run方法

@Override

public void run() {

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

System.out.println("吃了" + (i + 1) + "顿");

}

}

}

// 开启线程

public class MyThreadTestDemo {

public static void main(String[] args) {

// 创建线程对象,可以使用多态的方法创建, Thread m = new MyThreadDemo();

MyThreadDemo m = new MyThreadDemo();

// 开启线程

m.start();

// 线程开启后进入独立模块,CPU调度随机,也就是说两个线程随机运行

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

System.out.println("睡了" + (i + 1) + "天");

}

}

}

接口实现方式创建

自定义类实现Runnable接口

重写run方法,把线程任务封装进run方法

创建自定义对象

创建Thread类对象,将自定义对象作为参数传入Thread类创建对象的构造器

Thread对象调用start()方法,开启线程

// 实现Runnable接口创建线程

public class MyRunnable implements Runnable{ // 实现Runnable接口创建线程

// 重写run方法,将线程任务封装进run方法

@Override

public void run() {

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

System.out.println("吃了" + (i + 1) + "顿");

}

}

}

// 启动线程

public class MyRunnableDemo {

public static void main(String[] args) {

// 创建线程对象

MyRunnable m = new MyRunnable();

// 创建Thread类对象,将线程对象作为构造器参数传过去

Thread t = new Thread(m);

// 开启线程

t.start();

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

System.out.println("睡了" + (i + 1) + "天");

}

}

}

线程的生命周期

当程序创建一个线程以后,线程处于新建状态,无法被CPU调度,需要调用start()方法开启线程,调用start()方法之后线程进入就绪状态,等待CPU调度

当就绪状态的线程被CPU调度时进入运行状态,运行状态和就绪状态可以相互切换,当多个线程切换速度很快时,我们看起来就像多个线程在同步运行,这就是并发

运行状态可以切换到等待状态,它会等待另一个线程来执行一个任务,一个等待状态的线程只有通过另一个线程通知它转到可运行状态,才能继续执行

运行状态转到等待状态可以设置一个计时器,等待特定的时间之后唤醒线程对象

运行状态遇到异常或者其他特殊状况导致不能运行时进入阻塞状态,让出CPU调度,停止自身运行

当线程执行完或者抛出未捕获的异常和错误时,或者调用线程的stop()方法,线程终止,生命周期结束

操作线程的方法
智汇代理申请https://www.kaifx.cn/broker/t...

join方法: 主要作用是同步,它可以使得线程之间的并行执行变为串行执行.比如在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行

sleep方法: 让正在执行的线程暂停一段时间,进入阻塞状态.

// sleep(long milllis) throws InterruptedException; 毫秒为单位

Thread.sleep(1000); // 需要处理异常,使用try-catch

1

2

线程的优先级: 每个线程都有优先级,优先级的高低只和线程获得执行机会的次数多少有关,并不是说优先级高的就一定先执行,哪个线程的先运行取决于CPU的调度.Thread对象的setPriority(int x)和getPriority()用来设置和获得优先级,x的值不能大于线程执行的次数,否则报IllegalThreadStateException异常

后台线程: 守护线程,一般用于为其他线程提供服务,若前台线程都死亡,后台线程自动死亡.Thread对象setDaemon(true)用来设置后台线程,setDaemon(true)必须在start()调用前,否则抛出IllegalThreadStateException异常

线程安全性: 当多线程并发访问同一资源时会导致线程出现安全性的原因

需求: 现有100个苹果,现在有3个人去吃.

继承方式

// 线程类,继承Thread类

public class SafeThread extends Thread {

private int number = 100; // 苹果数量

public SafeThread(String name) { // 构造器,调用父类构造器把值传给父类

super(name);

}

// 重写run方法,把线程任务封装进去

public void run() {

for (int i = 0; i < 100; i++) {

if (number > 0) {

System.out.println(Thread.currentThread().getName()

+ "吃了第" + number-- + "个苹果");

}

}

}

}

// 测试类

public class SafeThreadDemo {

public static void main(String[] args) {

// 创建对象

Thread s1 = new SafeThread("xx");

Thread s2 = new SafeThread("yy");

Thread s3 = new SafeThread("zz");

// 开启线程

s1.start();

s2.start();

s3.start();

}

}

// 结果是3个人每个人都吃了100个苹果,继承方式多个线程不能共享同一资源

实现接口方式

// 创建线程类实现Runnable接口

public class SafeRunnable implements Runnable {

private int number = 100; // 苹果数量

// 重写run方法,把线程任务封装进去

public void run() {

for (int i = 0; i < 100; i++) {

if (number > 0) {

System.out.println(Thread.currentThread().getName()

+ "吃了第" + number-- + "个苹果");

}

}

}

}

// 测试类

public class SafeRunnableDemo {

public static void main(String[] args) {

// 创建线程对象

SafeRunnable s = new SafeRunnable();

// 创建Thread对象把线程对象当作参数参数传过去,开启线程

new Thread(s,"xx").start();

new Thread(s,"yy").start();

new Thread(s,"zz").start();

}

}

// 结果是3个人平分了100个苹果,实现方式可以多个线程共享同一资源

继承方式与实现方式的区别

Java中类是单继承,如果继承了Thread类就不能再继承其他类了,而实现方式不但可以再继承其他类,还可以实现多个接口,所以实现方法比较好用

继承方式多个线程没法共享同一资源,实现方式可以做到多个线程共享同一资源

线程同步

当多线程访问同一资源对象的时候可能会出现线程不安全的问题,实现Runnable接口创建线程的时候看起来可能没有问题,但是出现网络延迟的时候就会出现,这里用线程睡眠来模拟网络延迟

// 添加线程睡眠

public class SafeRunnable implements Runnable {

private int number = 100; // 苹果数量

// 重写run方法,把线程任务封装进去

public void run() {

for (int i = 0; i < 100; i++) {

if (number > 0) {

try {

Thread.sleep(100); // 让线程休眠0.1秒再运行,相当于网络出现0.1秒延迟

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()

+ "吃了第" + number-- + "个苹果");

}

}

}

}

// 测试类

public class SafeRunnableDemo {

public static void main(String[] args) {

// 创建线程对象

SafeRunnable s = new SafeRunnable();

// 创建Thread对象把线程对象当作参数参数传过去,开启线程

new Thread(s,"xx").start();

new Thread(s,"yy").start();

new Thread(s,"zz").start();

}

}

解决思路:在一个线程执行该任务的时候其他的线程不能来打扰,也就是设置一个同步锁,比如说A线程进入同步锁进行操作的时候,B和C以及其他的线程只能在外面等着,A操作结束,释放同步锁,A,B,C以及其他线程才会有机会去抢同步锁(A线程只要没有执行完所有任务,同样进入争夺同步锁的行列,谁获得同步锁,谁才能执行代码)

同步代码块

同步锁:

对于非static方法,同步锁就是this

对于static方法,同步锁就是当前方法所在类的字节码对象(.class文件)

public class SafeRunnable implements Runnable {

private int number = 100; // 苹果数量

// 重写run方法,把线程任务封装进去

public void run() {

for (int i = 0; i < 100; i++) {

/*

加同步锁

java允许使用任何对象作为同步监听对象

一般我们把当前并发访问的共同资源作为同步监听对象

这里的SafeRunnable对象拥有三个线程共同的资源,

而且只有一份,所以可以用来做同步锁

*/

synchronized (this) { // 加同步锁

if (number > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()

+ "吃了第" + number-- + "个苹果");

}

}

}

}

}

同步方法

public class SafeRunnable implements Runnable {

private int number = 100; // 苹果数量

// 重写run方法,把线程任务封装进去

public void run() {

for (int i = 0; i < 100; i++) {

doWork();

}

}

// synchronized修饰的方法是同步方法

synchronized public void doWork() {

if (number > 0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()

+ "吃了第" + number-- + "个苹果");

}

}

}

synchronized的优劣势

好处: 保证了多线程并发访问时的同步操作,避免线程的安全性问题

缺点: 使用synchronized的方法/代码块的性能要低一些

建议: 尽量减小synchronized的作用域


zhuanzhudeyipi
65 声望2 粉丝