(一)目录
(二)多线程介绍
1.多线程的基本概念
-
进程是程序的一次动态执行过程, 占用特定的地址空间。
-
每个进程由 3 部分组成:cpu、data、code。每个进程都是独立的,保有自 己的 cpu 时间,代码和数据,即便用同一份程序产生好几个进程,它们之间还是拥有自己的这 3 样东西,这样的缺点是:浪费内存,cpu 的负担较重。
-
多任务(Multitasking)操作系统将 CPU 时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独立运行。以进程的观点来看,它会以为自己独占 CPU 的使用权。
-
进程的查看 :Windows 系统: Ctrl+Alt+Del,启动任务管理器即可查看所有进程。
线程
一个进程可以产生多个线程。同多个进程可以共享操作系统的某些资源一样,同一进程
-
一个进程内部的一个执行单元,它是程序中的一个单一的顺序控制流程。
-
一个进程可拥有多个并行的(concurrent)线程。
-
一个进程中的多个线程共享相同的内存单元/内存地址空间,可以访问相同的变量和对象,而且它们从同一堆中分配对象并进行通信、数据交换和同步操作。
-
由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制, 这就使得通信更简便而且信息传递的速度也更快。
-
线程的启动、中断、消亡,消耗的资源非常少。
2.线程和进程的区别
-
线程在进程中运行的。
-
一个进程可以包含多个线程。
-
不同进程间数据很难共享,而同一进程下不同线程间数据很易共享。
-
进程要比线程消耗更多的计算机资源。
-
进程间不会相互影响,因为它们的空间是完全隔离的。而进程中的一个线程挂掉将导致整个进程挂掉。
-
进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
-
一个进程如果只有一个线程则可以被看作单线程的,如果一个进程内拥有多个线程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
3 并发
并发是指在一段时间内同时做多个事情。当有多个线程在运行时,如果只有一个 CPU,这种情况下计算机操作系统会采用并发技术实现并发运行,具体做法是采用“ 时间片轮询算法”,在一个时间段的线程代码运行时,其它线程处于就绪状。这种方式我们称之为并发(Concurrent)。
4 线程的执行特点
4.2线程的执行特点
5 主线程以及子线程
(三)创建线程
public class TestThread extends Thread {
public TestThread(){
System.out.println(this.getName());
}
/**
* 线程的线程体
*/
@Override
public void run() {
System.out.println(this.getName()+"线程开始");
for(int i=0;i<20;i++){
System.out.println(this.getName()+" "+i);
7
}
System.out.println(this.getName()+"线程结束");
}
public static void main(String[] args) {
System.out.println("主线程开始");
TestThread t1 = new TestThread();
//启动线程
t1.start();
TestThread t2 = new TestThread();
//启动线程
t2.start();
System.out.println("主线程结束");
}
}
public class TestThread2 implements Runnable {
public TestThread2(){
System.out.println(Thread.currentThread().getName());
}
/**
* 当前线程的线程体方法
*/
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 线程开
始");
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName()+"
"+i);
}
8
System.out.println(Thread.currentThread().getName()+" 线程结
束");
}
public static void main(String[] args) {
System.out.println("主线程开始");
TestThread2 testThread2 = new TestThread2();
Thread t1 = new Thread(testThread2);
t1.start();
Thread t2 = new Thread(new TestThread2());
t2.start();
System.out.println("主线程结束");
}
}
4 线程的生命周期
简言之,一个线程对象在它的生命周期内,需要经历 5 个状态。(新生、就绪、运行、堵塞、死亡)。
(三) 线程的使用
1 终止线程
public class StopThread implements Runnable {
private boolean flag = true;
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" 线程开
始");
int i= 0;
while(flag){
System.out.println(Thread.currentThread().getName()+" "+i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" 线程结
束");
12
}
public void stop(){
this.flag = false;
}
public static void main(String[] args)throws Exception {
System.out.println("主线程开始");
StopThread st = new StopThread();
Thread t1 = new Thread(st);
t1.start();
System.in.read();
st.stop();
System.out.println("主线程结束");
}
}
2 暂停当前线程执行 sleep/yield
-
yield 是一个静态的方法。
-
调用 yield 后,yield 告诉当前线程把运行机会交给具有相同优先级的线程。
-
yield 不能保证,当前线程迅速从运行状态切换到就绪状态。
-
yield 只能是将当前线程从运行状态转换到就绪状态,而不能是等待或者阻塞状态。
3 线程的联合
/**
* 儿子买烟线程
*/
class SonThread implements Runnable{
@Override
public void run() {
System.out.println("儿子出门买烟");
System.out.println("儿子买烟需要 10 分钟");
for(int i=0;i<10;i++){
System.out.println("第"+i+"分钟");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("儿子买烟回来了");
}
}
/**
* 爸爸抽烟线程
*/
17
class FatherThread implements Runnable{
@Override
public void run() {
System.out.println("爸爸想抽烟,发现烟抽完了");
System.out.println("爸爸让儿子去买一包红塔山");
Thread t = new Thread(new SonThread());
t.start();
System.out.println("等待儿子买烟回来");
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("爸爸出门找儿子");
System.exit(1);
}
System.out.println("爸爸高兴的接过烟,并把零钱给了儿子");
}
}
public class JoinDemo {
public static void main(String[] args) {
System.out.println("爸爸和儿子买烟的故事");
Thread t = new Thread(new FatherThread());
t.start();
}
}
4 Thread 类中的其他常用方法
class GetName1 extends Thread{@Overridepublic void run() {System. out .println( this .getName());}}
class GetName2 implements Runnable{@Overridepublic void run() {System. out .println(Thread. currentThread ().getName());}}
class SetName1 extends Thread{public SetName1(String name){super (name);}@Overridepublic void run() {System. out .println( this .getName());}}public class SetNameThread {public static void main(String[] args) {SetName1 setName1 = new SetName1( "SetName1" );setName1.start();}}
class SetName2 implements Runnable{@Overridepublic void run() {System. out .println(Thread. currentThread ().getName());}}public class SetNameThread {public static void main(String[] args) {/*SetName1 setName1 = new SetName1();setName1.setName("SetName1");setName1.start();*/Thread thread = new Thread( new SetName2());thread.setName( "SetName2" );thread.start();}}
class Alive implements Runnable{@Overridepublic void run() {System. out .println(Thread. currentThread ().isAlive()+ " 2" );try {Thread. sleep ( 20000 );} catch (InterruptedException e) {20 e.printStackTrace();}}}public class AliveThread {public static void main(String[] args) {Thread thread = new Thread( new Alive());System. out .println(thread.isAlive()+ " 1" );thread.start();System. out .println(thread.isAlive()+ " 3" );try {Thread. sleep ( 1000 );} catch (InterruptedException e) {e.printStackTrace();}System. out .println(thread.isAlive()+ " 4" );}}