java基础之 多线程

多线程

## 概述
多线程是为了解决,提高程序的执行效率或者从根本上提高CPU的执行效率
## 进程和线程
进程 就是正在运行的程序,一个软件的运行可以有一个或者多个进程
线程 操作系统能够进行运算调度的最小单位,是进程的实际运作单位
一个软件的运行至少依赖一个进程 ,一个进程的运行至少依赖一个线程
进程有独立的存储空间,可以存线程,也可以有多个线程共享的空间、
线程有独立空间,线程间暂时无法通信。线程之间也是独立的。
## 并发和并行
并发  是指多个程序抢占同一个CPU资源
并行  有多个cpu 每个cpu只负责一件事情 没有发生抢占现象
##  多线程特点
	1. 随机性 操作系统的程序执行权,会交给CPU ,CPU我们控制不了,全部由操作系统调度
	2.  线程状态
	新建状态 , 可运行状态 ,运行状态 ,终止状态, 阻塞状态
## 多线程编程  ---继承Thread类
	1. 创建对象
	     Thread(); 分配新的线程对象
	     Thread(Runnable target); 
	     Thread(Runnable target, String name);
	     Thread(String name);
	 2.常用方法
	 	static Thread currentThread();
	 	long getId();//返回该线程的标识符 (ID)
	 	String  getName(); 返回线程名称
	 	void  setName()设定名称
	 	static void sleep(long millis)
	 	void run()
	 	void start() 开始执行线程
//继承Thread类
package cn.tedu.thread;
		//这个类用来测试  多线程编程
		public class Test1_Thread {
		    public static void main(String[] args) {
		    //5.创建线程对象
				Mythread target = new Mythread();//新建状态
				Mythread target2 = new Mythread();
			//6. 开启线程 并执行线程run里面的业务
			target.start();//可运行状态 等待cpu调度
			target2.start();
			/*
			 8、多线程执行结果的随机性,由于CPU执行过程不可控,所以会出现随机结果
		        Thread-0120
		        Thread-0122
		        Thread-1130
		        Thread-0123
		        Thread-1131
		        Thread-0124
		        Thread-0125	
		      */		
}
class Mythread extends Thread{
	//2.把所有的业务放入重写的run方法中 
	@Override
	public void run(){
		//3、打印10次线程信息 --  fori提示普通循环
		        for (int i = 0; i < 10 ; i++) {
		            //4、sout提示输出语句
		            System.out.println(getName()+"="+getId()+"="+i);
		        }
	}

}

多线程编程 2 实现Runnable接口

	package cn.tedu.thread;
		//这个类用来测试 多线程编程
		public class Test2_Runnable {
		    public static void main(String[] args) {
			//4.创建线程对象
			MyRunnable target =new MyRunnable();
			//5.绑定Runnable接口和Thread类的关系
			Thread t1= new Thread(target,"aa");
			Thread t2 = new Thread(target,"bb");
			//t1.setName("aa");
			//t2.setName("bb");
			//6.启动线程
			t1,start();
			t2.start();
			
		        /*多线程程序的随机性
		        Thread-0===0
		        Thread-1===0
		        Thread-0===1
		        Thread-0===2
		        Thread-0===3
		        Thread-1===1
		        Thread-0===4
		        Thread-1===2
		        Thread-1===3
		        */
}
}
//1. 创建多线程类 并实现Runnable接口
class MyRunnable implements Runnable{
	//2. 八所要执行的业务放入重写的Run()
	@Override
	 public void run() {
	 for (int i = 0; i < 20 ; i++) {
		//3.输出线程名称 因为没有继承Thread类 所以只能调用Thread类中的静态方法
		//Thread.currentThread获取正在执行的线程
	 System.out.println(Thread.currentThread().getName() +"=="+i);	

		}
		         
  }
}

模拟售票 案例 (多线程安全性)

package cn.tedu.thread;

		//这个类用来测试 多线程售票
		//TODO  为什么数据会出错,分析程序???
		//TODO  怎么解决多线程编程中的数据安全隐患???
		//TODO  多操作IDEA
		public class Test3_Tickts {
		    public static void main(String[] args) {
		        //3、创建线程对象
		        MyTickets t1 = new MyTickets();
		        MyTickets t2 = new MyTickets();
		        MyTickets t3 = new MyTickets();
		        MyTickets t4 = new MyTickets();
		        t1.start();
		        t2.start();
		        t3.start();
		        t4.start();
		        //4、问题1:需要是卖100张票,目前卖了400张票。为什么?因为tickets是实例变量
		        //每次new都会给对象初始化,4个对象,就初始化了4次有了400张票。--怎么解决?
		        //如果能把tickets变成多个对象间共享的就可以了?--
		    }
		}
		//1、模拟多线程开发
		class MyTickets extends Thread {
		    //定义变量,记录100张票
		//  int tickets = 100; //4.1、实例变量,会new多次就拥有多张票
		    static  int tickets = 100;//4.2、变量共享资源
		    //2、开始卖票 ,写进run()
		    @Override
		    public void run() {
		        while (true) {//一直卖票
		            if (tickets > 0) {
		                try {
		                    //5、检查多线程数据有没有安全隐患,最终的大招就是让程序休眠一会10ms
		                    //问题2多卖:同一张票卖给了多个人
		                    //问题3超卖:卖出了0号票
		                    Thread.sleep(10);
		                } catch (InterruptedException e) {
		                    e.printStackTrace();
		                }
		                System.out.println(getName() + ":" + tickets--);
		            } else {
		                break;//票数<=0就结束
		            }
		        }
		    }
		}


同步锁

--1、原理:是指给你的共享资源加锁。还是可以让多个线程操作共享资源,只不过哪个线程有钥匙,
      拿着钥匙进来开锁使用共享资源,没有钥匙的线程等待。--同步的锁,
--2、同步和异步的区别:
	--同步:是需要拿着钥匙开锁,同一时刻只能有一个线程操作共享资源,其他线程排队等待。			  
	  牺牲了效率,提高了安全。
	--异步:是没有排队的现象,大家同时使用了共享资源。提高了效率,牺牲了数据安全。
	--举例:可以看做是你使用教室的门这个共享资源的过程
--3、语法
 synchronized(对象){ 需要同步的代码块 }
--4. 使用锁
  • 多线程安全 是由于线程的随机访问和访问的延迟所导致
  • 在多线程编程中 如果有共享资源 并且这条资源被多条语句操作 那么就存在安全隐患
  • 锁的位置 : 要合适 不能太大 会影响效率 不能太小 相当于没锁住
  • 锁的对象:要求多个线程之间 使用的是同一把锁
  • 使用范围 :可以用在方法上 也可以用在代码块上

改造的售票案例

class MyTickets implements Runnable{
	int tickets = 100;//定义变量 记录票数
	Object obj = new Object();
	@Override
	//public synchronized void run(){ 锁方法 默认使用的对象是this  把整个方法锁起来,虽然降低了效率,但提高了安全性
	public synchronized void run(){
	whiletrue{//一直卖票
	//1. 可以把有安全隐患的 代码 锁起来 --- 同步锁的代码块
	//2. 锁的位置 不能太大也不能太小 建议从共享资源开始的位置一直到使用结束 都锁起来
	//3.锁的对象 锁代码的对象可以是任意对象 只要是同一对象就可以
	//synchronizaed(new Object()){ //这样锁不住 因为每个线程近来都用的不是同一个对象
	//synchronized(obj) 这种能锁住 都是同一对象  不过不建议 太麻烦
	synchronized(this){
		if (tickets > 0) {//有票就卖
		  try {
		      Thread.sleep(10);//让程序休眠10ms
		 } catch (InterruptedException e) {
		            e.printStackTrace();
		     }
	 System.out.println(Thread.currentThread().getName() + " ~ " + tickets--);
		   } else {
		         break; //结束死循环
		          }

}
}
	
}

}

猜你喜欢

转载自blog.csdn.net/m0_49731762/article/details/107896790