小白都能看懂的-------->多线程

Day4:
一:关于多线程概述和简单使用
1.同步代码块:创建实现子类继承Thread类,重写run方法
注意:在Java中线程调度是抢占式的
多线程的底层原理:
当线程开始执行的时候,共享变量会拷贝一份到独立的工作内存空间,并且在工作内存空间中对共享变量进行所有操作,不会读写主内存中的变量。
扩展:一个线程类,最少有两个线程(主线程,子线程)主线程就是常写的main方法,子线程就是自己定义的线程。
创建线程有两种方式:
1.1:子类继承Thread,重写run方法
1.2:子类实现Runnable,重写run方法
1.3:锁的概念:当一个线程中添加了锁,那么该锁下面的就将进入到无限等待,只有到其他线程中解开该线程的锁,线程才会停止等待,执行锁下面的代码
1.4:synchronized这个又叫悲观锁:指定的是用synchronized保证线程同步

二:高进程和线程安全
第一种:

class Synchronized1{
	public static void main(String []args){
	Show show=new Show();
	Show  show1=new Show("线程一");
	show.start();       //一个线程
	show1.start();     //两个线程
}
}
classs Show extends Thread{
	int num=100;
	 @Override
	public void run(){
	while(true){
	//这里使用this,谁创建该类对象,谁就是这个的this
		synchronized(this){
			if(num<1){
				break;
			}
			else{
				try{
				//如果判断不是小于1,那么就睡眠一秒
					Thread.sleep(1000);
				}
				catch(InterruptedException e){
						e.printStackTrace();
				}
				//获取到当前前程的名字Thread.currentThread().getname
				System.out.println(Thread.currentThread().getName+"抢到票"+num);
				num--;
			}
		}
		}
	}

}

第二种实现Runnable:

class Test{
	public static void main(String []args){
		Show show=new Show();
		
		new Thread(show,"线程一").start();
		new Thread(show,"线程二").start();
}
}
class Show implements Runnable{
	int num=100;
	@Override
	public void run(){
		for(int i=0;i>100;i++){
			System.out.println(Thread.currentThread.getName()+"获取到票"+i);
		}
	}
}

扩展:同步锁:

class Test{
	public static void main(String [] args){
		A a=new A("线程一");
		B b=new B();
		a.start();
		new Thread(b,"线程二").start();
		//输出:
		//java是抢占式的;所以线程是抢占的,那个线程抢占到cpu,谁就开始执行
		//输出的是:
			//概念:执行到抢占到的线程,如果线程执行完,重新从头抢占
}
}

第一个方式添加同步锁:

class A extends Thread{
B  b=new B();
int num=100;
		@Override
		public void run(){
			while(true){
				synchronized(B.class){
					if(num<100){
						break;
					}else{
						System.out.println(Thread.currentThread.getName()+"获取到票"+num);
					}
					num--;
				}
			}
			
	}
}

第二个方式添加同步锁:

class B implements Runnable{
	@Override
	public void run(){
		for(int i=0;i<100;i++){
			System.out.println(Thread.currentThread.getName()+"获取到票"+i);
		}
	}
	
}

二关于多线程安全和高并发
1:高并发概述:就是在同一个时间点,同时访问一个线程数据
2:线程安全:就是指在同一时间线程访问同一资源,由于线程运行机制的原因,可能会出现数据污染的问题
1:可见性概述:就是指一个线程没有看到另外一个线程修改了成员变量;

1:可见性:

calss Test{
	public static void main(String [] args){
			Show  show=new Show("线程一");
			show.start();
			while(true){
			if(show.flag==true){
				System.out.println("Test中输出的flag为:"+flag);
			}
	}
			//输出结果
			//flag是true,但是在Test方法中if中的方法,不会被执行
		}
}
classs Show extends Thread{
static boolean  flag=true;
	@Override
	public void run(){
		try{
			Thread.sleep(5000);
	}
	catch(InterruptedException e){
			e.printStackTrace();
	}
	flag=true;
	System.out.println("flag是:"+flag);
}
}

可见性运行机制:
概括:就是在独立的工作内存中对共享变量进行了修改,但是主线程没有发现。在这里插入图片描述

2:有序性:
概述:就是在代码中执行的顺序不是按照从上往下来执行的,也有可能是先在方法中执行第二行中的代码在执行第一行的代码,这就是代码的重排。
class Test{
	public static void main(String [] args){
		Show  show =new Show();
		new Thread(show,"线程一").start()
	}
}
class Show implements Runnable{
	@Override
	public void run(){
		int a=10;
		int b=20;    //有可能是从b开始执行的,然后在执行a中的,但是不影响c的使用,但是在多线程中代码被重排,可能会对线程访问产生影响
		int c=a+b;
		for(int i=0;i<c;i++){
			System.out.println("这是i的第"+i+"个");
		}
	}
}
3:原子性:
概述:就是在线程执行的时候,独立工作内存空间将共享变量拷贝到独立内存中,当线程一对共享变量进行修改,那么共享变量会重新传回到主内存中,但是,线程二还是原来从主内存拷贝过来的共享变量,那么线程二就会进行判断,如果是相同的,那么就修改,如果是不同的那么就重新往主内存中拷贝新的共享变量,在进行修改,所以,在原子性的情况下,预想的值要比实际的值要低,这就是线程的覆盖效果。
class Test{
	public static void main(){
		Show show=new Show();
		new Thread(show,"线程一").start();
		new Thread(new Runnable{
				@Override
				public void run(){
					for(int i=0; i<100000;i++){
						show.a++;
					}
					System.out.println("a:"+show.a);
				}
		}).start();
		
	}
}

class Show implements Runnable{
	static int a=0;
	@Override
	public void run(){
			for(int i=0 ;i<100000;i++){
				a++;
		}
		try{
			Thread.sleep(1000);
		
  } catch (InterruptedException e) {
            e.printStackTrace();
		
	}
	System.out.println("子线程执行完毕");		
}

输出的结果:可能会是等于200000,也有可能是小于200000;
在这里插入图片描述
解决线程中的可见性和有序性(volatile):
概述:只要在共享变量中添加上volatile,就可以避免出现线程中的可见性,和有序性

class Show implements Runnable{
	static  volatile int a=0;
	@Override
	public void run(){
			for(int i=0 ;i<100000;i++){
				a++;
		}
		try{
			Thread.sleep(1000);
		
  } catch (InterruptedException e) {
            e.printStackTrace();
		
	}
	System.out.println("子线程执行完毕");		
}

解决代码中的可见性和有序性和原子性(AtomicInteger ):
AtomicInteger :这是在int类型中的改写方式
AtomicInteger Array:跟上面integer书写方式一样,但是这是数组的方式

//这里就直接改写Show方法,Test方法上述不变
class Show implements Runnable{
//改写a的类型定义方式
	static AtomicInteger a=new AtomicInteger();
	@Override
	public void run(){
			for(int i=0 ;i<100000;i++){
			//a++,因为上述中改写了a的类型定义方式,所以自增的方式也要用定义的方式的来调用;
				a.getAndIncrement();
		}
		try{
			Thread.sleep(1000);
		
  } catch (InterruptedException e) {
            e.printStackTrace();
		
	}
	System.out.println("子线程执行完毕");		
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值