并发编程(01)--多线程基础

Posted cryptonym

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程(01)--多线程基础相关的知识,希望对你有一定的参考价值。

1.关于多线程

1.1 线程与进程的区别

进程:系统中每一个正在运行的程序都是一个进程,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元

线程:是一组指令的集合,控制着进程的执行,一个进程中至少有一个线程

1.2 为什么用多线程

使用多线程可以将执行时间长的程序中的任务放到后台去处理,在一些需要等待的任务上如文件读写、网络分发数据等,使用多线程就可以更好的利用CPU的资源,从而提高程序运行的效率

2. 线程的状态

线程有5种状态:新建、就绪、运行、阻塞、死亡,如下图所示:

技术图片

新建状态:当new一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码

就绪状态:一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由java运行时系统的线程调度程序(thread scheduler)来调度的。

运行状态:当线程竞争到CPU时间之后,执行run()方法,进入运行状态

阻塞状态:线程运行过程中,可能由于各种原因进入阻塞状态:

1)线程通过调用sleep方法进入睡眠状态;

2)线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;

3)线程试图得到一个锁,而该锁正被其他线程持有;

4)线程在等待某个触发条件;

所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

死亡状态:有两种原因会导致线程进入死亡状态:

1)run()方法执行完成正常死亡

2)发生异常终止了run()方法而进入死亡状态

3. 创建线程的方法

3.1 继承Thread类,重写run()方法

class CreateThread extends Thread {
	
	publicvoid run() {
		// run方法中编写 多线程需要执行的代码
	}
}

3.2 实现Runnable接口,重写run()方法

class CreateRunnable implements Runnable {

	@Override
	publicvoid run() {
		//run方法中编写多线程需要执行的代码
	}

}

3.3 匿名内部类方式

Thread thread = new Thread(new Runnable() {
			public void run() {
				//run方法中编写多线程需要执行的代码
			}
});

4. 常用的方法

4.1 join()

join():当线程B执行到了线程A的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行,join可以用来临时加入线程执行。

public class Thread002 {

	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.print("这个是t1线程:" + i +"	");
				}
				System.out.println("
--------------分割线------------------");
			}
		});

		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					t1.join();
					
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				for (int i = 0; i < 10; i++) {
					System.out.print("这个是t2线程:" + i+ "	");
				}
				System.out.println("
--------------分割线------------------");
			}
		});

		Thread t3 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					t2.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				for (int i = 0; i < 10; i++) {
					System.out.print("这个是t3线程:" + i +"	");
				}
				
			}
		});
		t1.start();
		t2.start();
		t3.start();

	}

}

4.2 sleep()、yield()

sleep():让正在执行的线程休眠,因为使用sleep方法之后,线程是进入阻塞状态的,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒

public class SynTest {
    public static void main(String[] args) {
        new Thread(new CountDown(),"倒计时").start();
    }
}

class CountDown implements Runnable{
    int time = 10;
    public void run() {
        while (true) {
            if(time>=0){
                System.out.println(Thread.currentThread().getName() + ":" + time--);
                try {
                    Thread.sleep(1000);                                                    //睡眠时间为1秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

yield():和sleep方法类似,也是Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。相当于只是将当前线程暂停一下,然后重新进入就绪的线程池中,让线程调度器重新调度一次。也会出现某个线程调用yield方法后暂停,但之后调度器又将其调度出来重新进入到运行状态

public class SynTest {
    public static void main(String[] args) {
        yieldDemo ms = new yieldDemo();
        Thread t1 = new Thread(ms,"张三吃完还剩");
        Thread t2 = new Thread(ms,"李四吃完还剩");
        Thread t3 = new Thread(ms,"王五吃完还剩");
        t1.start();
        t2.start();
        t3.start();
    }
}
class yieldDemo implements Runnable{
    int count = 20;
    public void run() {
        while (true) {
                if(count>0){
                    System.out.println(Thread.currentThread().getName() + count-- + "个瓜");
                    if(count % 2 == 0){
                        Thread.yield();                  //线程让步
                    }
            }
        }
    }
}

以上是关于并发编程(01)--多线程基础的主要内容,如果未能解决你的问题,请参考以下文章

python并发编程之多线程基础知识点

并发编程基础01-线程安全

并发编程多线程基础

并发编程之多线程基础-守护线程与非守护线程

并发编程之多线程基础篇及面试

并发编程