java进程、线程、线程生命周期,创建线程的五种方法、以及多线程并发同步问题。

1.程序、进程、线程、并行、并发

程序:一段静态的代码。

进程:程序的一次动态执行过程。进程基于操作系统,运行在内存中。如windows就是一个多任务系统,可以同时运行多个应用程序。

线程:在一个程序中同时运行的多个独立的流程,每一个独立的流程就是线程。

进程和线程有时也被称为任务。

线程并发:多个线程并发执行。

并行:并行是指两个或者多个事件在同一时刻发生,同时运行。只有具备多个cpu才能实现并行。

并发:并发是指两个或多个事件在同一时间间隔发生。是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发。

而无论是并行还是并发,在用户看来都是“同时”运行的。

主线程:当JVM启动后,加载类文件,发现main方法,那么就会为main方法创建一个线程,这个为main方法创建的线程称为主线程。

一个进程中可以有多个任务一起执行,每一个任务都被称为一个线程。线程依赖于进程,在进程中运行·,不能独立存在。每个进程中至少有一个线程,被称为主线程。只有当程序中所有的线程都结束之后,程序才会结束。

线程随机性:正常情况下,线程是随机的,谁先执行是不确定的,如果我们想控制顺序,需要自己编写代码。

2.创建线程的五种写法以及java中多线程代码的编写

方法1:直接Thread t=new Thread(); t.start(); 这种方法程序可以运行,但没有什么意义,因为原始线程run()方法里什么也没有。start开始即结束。
方法2:继承Thread,重写run方法;
方法3:实现Runnable ,new Thread();
方法4:Thread匿名内部类
方法5:Runnable匿名内部类

下面给出用五种方法来创建线程的代码示例:
定义EatThread类,继承Thread,重写run()方法

package test;
//继承Thread,重写run()方法
public class EatThread extends Thread {
	
	@Override
	public void run() {
		
		for(int i=1;i<3;i++)
		{
			
			//每隔0.1秒吃一口
			System.out.println(this.getName()+"吃一口!");
			try {
				
				//等待0.1秒
				 sleep(100); //也可以写成this.sleep(100)或者Thread.sleep(100);
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(this.getName()+"线程结束");
	}
}

定义PhoneThread类,实现Runnable接口

package test;
//实现Runnable接口
public class PhoneThread  implements Runnable {
	
	@Override
	public void run() {
		
		//获取当前正在执行这段代码的线程
		Thread now =Thread.currentThread();
		for(int i=1;i<3;i++)
		{		
			//每隔0.1秒玩一次手机
			System.out.println(now.getName()+"玩手机");//注意:此处不能写成this.getName()
			try {
				
				//等待0.1秒
				 now.sleep(100); //或者写成Thread.sleep(100) 
				                 //注意:此处不能写成sleep(100)或者this.sleep(100),会报错				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(now.getName()+"线程结束");
	}
}

主函数,五种创建方法

package test;

public class Test {

	public static void main(String[] args) {
		
		/**
		 * 第一种:直接new thread(),这种方法没有什么意义
		 */
		Thread t1=new Thread();
		t1.setName("1");
		t1.start();
		/**
		 * 第二种,继承Thread,重写run()方法
		 */
		EatThread t2=new EatThread();
		t2.setName("2");
		t2.start();
		/**
		 * 第三种,实现Runnable接口
		 */
		PhoneThread pt=new PhoneThread();
		Thread t3=new Thread(pt); 
		Thread t4=new Thread(new PhoneThread());//此处也可以写成Thread t4=new Thread(pt);
		t3.setName("3");//也可以在创建线程的时候直接命名Thread t3=new Thread(pt,"3");
		t4.setName("4");
		t3.start();
		t4.start();
		/**
		 * 第四种,Thread匿名内部类,仅适合局部使用
		 */
		new Thread("5") {
			@Override
			public void run() {
				for(int i=1;i<3;i++)
				{				
					//每隔0.1秒站一下
					System.out.println(this.getName()+"站起来!");
					try {
						
						//等待0.1秒
						 sleep(100); //也可以写成this.sleep(100)或者Thread.sleep(100);
						
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(this.getName()+"线程结束");
			}
		}.start();
		/**
		 * 第五种:Runnable匿名内部类
		 */
		Thread t6=new Thread(new Runnable() {
			
			
			@Override
			public void run() {
				Thread now=Thread.currentThread();
				for(int i=1;i<3;i++)
				{				
					//每隔0.1秒坐一下
					System.out.println(now.getName()+"坐下去!");
					try {
						
						//等待0.1秒
						 Thread.sleep(100); //或者now.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(now.getName()+"线程结束");
			}
			
		},"6");
		
		t6.start();			
	}
}

运行结果:

2吃一口!
3玩手机
4玩手机
5站起来!
6坐下去!
3玩手机
2吃一口!
4玩手机
6坐下去!
5站起来!
3线程结束
2线程结束
5线程结束
6线程结束
4线程结束

3.线程的生命周期

新建、就绪、运行、阻塞、死亡总共5种状态
(1)新建:创建一个线程;

(2)就绪:执行start()之后就处于就绪状态,时刻准备着被cpu执行。

(3)运行:线程得到了cpu资源进行运行,但只有一小段时间片;时间到了之后,cpu就切换到其他线程,当前线程又变为就绪状态。

(4)堵塞:睡眠sleep(毫秒)、等待wait()、等待队列join()、

(5)死亡:run执行结束或者中途被其他线程杀死

自然死亡:正常运行run()方法结束后终止

异常终止:调用stop()等方法杀死

4.多线程同步问题

以存钱取钱为例,说明线程同步问题。

先看如下代码,张三存钱,存10次,每次存100元。李四取钱,取10次,每次取100元。

package test;

//账户
public class Account {
	
	static  private double n; //定义账户余额

	public double getN() {
		return n;
	}

	public void setN(double n) {
		this.n = n;
	}	
}
package test;

public class Tongbu {

	public static void main(String[] args) {
		
		Account ac =new Account();
		ac.setN(1000); //账户当前余额1000元
		System.out.println("最开始余额为:"+ac.getN());
		
		new Thread("张三") {
			@Override
			public void run() {
				try {
					for(int i=1;i<=10;i++) {
						//获取当前账户余额
						double n=ac.getN();
						
						//向账户中存出100
						n=n+100;
						sleep(1);		
						ac.setN(n);
						
						//输出当前账户余额
						System.out.println(this.getName()+"存100后余额为:"+n);					
					}
					
				  }catch (InterruptedException e) {
					  e.printStackTrace();
				}		
			}
		}.start();
		
		new Thread("李四") {
			@Override
			public void run() {
			try {
				for(int i=1;i<=10;i++) {
					//获取当前账户余额
					double n=ac.getN();
					
					//从账户中取出100
					n=n-100;
					sleep(1);		
					ac.setN(n);
					
					//输出当前账户余额
					System.out.println(this.getName()+"取100后余额为:"+n);					
				}
				
			  }catch (InterruptedException e) {
				  e.printStackTrace();
			}		
		}
	}.start();
}

}

运行结果为:

最开始余额为:1000.0
张三存100余额后为:1100.0
李四取100后余额为:900.0
张三存100余额后为:1200.0
李四取100后余额为:800.0
张三存100余额后为:1300.0
李四取100后余额为:700.0
张三存100余额后为:1400.0
李四取100后余额为:600.0
张三存100余额后为:1500.0
李四取100后余额为:500.0
张三存100余额后为:1600.0
李四取100后余额为:400.0
张三存100余额后为:1700.0
李四取100后余额为:300.0
张三存100余额后为:1800.0
李四取100后余额为:200.0
张三存100余额后为:1900.0
李四取100后余额为:100.0
张三存100余额后为:2000.0
李四取100后余额为:0.0

从上面的结果看出,这并不是我们想要的结果,最终余额应该仍为1000。

解决方案:加锁,synchronized

synchronized里面的代码是一个整体,必须执行完,即使里面有sleep,其他的线程也要等待这一段执行完。

synchronized:线程同步,让线程排队。
:使用不同的锁就有不同的队伍

package test;

public class Tongbu {

	public static void main(String[] args) {
		
		Account ac =new Account();
		ac.setN(1000); //账户当前余额1000元
		System.out.println("最开始余额为:"+ac.getN());
		
		new Thread("张三") {
			@Override
			public void run() {
				try {
					
						for(int i=1;i<=10;i++) {
						//加锁,ac为大家都认识的对象,不能加一个只有你自己认识的锁
							synchronized(ac) {
								//获取当前账户余额
								double n=ac.getN();
								
								//向账户中存出100
								n=n+100;
								sleep(1);		
								ac.setN(n);
								
								//输出当前账户余额
								System.out.println(this.getName()+"存100后余额为:"+n);	
							} 											
						}										
					
				  }catch (InterruptedException e) {
					  e.printStackTrace();
				}		
			}
		}.start();
		
		new Thread("李四") {
			@Override
			public void run() {
			try {
				for(int i=1;i<=10;i++) {
					//加锁,ac为大家都认识的对象
					synchronized(ac) {
						//获取当前账户余额
						double n=ac.getN();
						
						//从账户中取出100
						n=n-100;
						sleep(1);		
						ac.setN(n);
						
						//输出当前账户余额
						System.out.println(this.getName()+"取100后余额为:"+n);		
					}
								
				}
				
			  }catch (InterruptedException e) {
				  e.printStackTrace();
			}		
		}
	}.start();
	}
}

运行结果:

最开始余额为:1000.0
张三存100后余额为:1100.0
张三存100后余额为:1200.0
张三存100后余额为:1300.0
张三存100后余额为:1400.0
张三存100后余额为:1500.0
李四取100后余额为:1400.0
李四取100后余额为:1300.0
李四取100后余额为:1200.0
李四取100后余额为:1100.0
李四取100后余额为:1000.0
李四取100后余额为:900.0
李四取100后余额为:800.0
李四取100后余额为:700.0
李四取100后余额为:600.0
李四取100后余额为:500.0
张三存100后余额为:600.0
张三存100后余额为:700.0
张三存100后余额为:800.0
张三存100后余额为:900.0
张三存100后余额为:1000.0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值