学习Java多线程看这篇就够了(建议收藏)

学习Java多线程看这篇就够了

  • 多线程学习篇
    • 1、多线程_概念
    • 2、多线程_继承Thread
    • 3、多线程_图片下载
    • 4、多线程_实现Runnable
    • 5、多线程_抢票_龟兔赛跑
      • 1)模拟购票
      • 2)模拟龟兔赛跑
    • 6、多线程_了解Callable
    • 7、多线程_静态代理设计模式
    • 8、多线程_Lambada_简化线程
    • 9、多线程_终止
    • 10、多线程_暂停sleep
    • 11、多线程_礼让yield
    • 12、多线程_插队join
    • 13、多线程_深度观察状态
    • 14、多线程_优先级
    • 15、多线程_守护线程
    • 16、多线程_基本信息_网红思维
    • 17、多线程_并发_非同步_三大经典案例
    • 18、多线程_并发_同步_队列与锁
    • 19、多线程_并发_同步_synchronized同步块
    • 20、多线程_并发_同步_性能分析
    • 21、多线程_并发_同步_快乐影院
    • 22、多线程_并发_死锁_产生与解决
    • 23、多线程_并发协作_生产者消费者模型
    • 24、多线程_并发协作_管程法
    • 25、多线程_并发协作_信号灯
    • 26、多线程_高级主题_定时调度
    • 27、多线程_高级主题_QUARTZ
    • 28、多线程_高级主题_happenbefore
    • 29、多线程_高级主题_volatile
    • 30、多线程_高级主题_dcl单例模式
    • 31、多线程_高级主题_ThreadLocal
    • 32、多线程_高级主题_可重入锁_原理实现
      • 1)可重入锁:锁可以延续使用
      • 2)不可重入锁
    • 33、多线程_高级主题_CAS_原子操作

好文推荐:排序、查找算法齐全(程序员必会 好文 值得收藏!)

多线程学习篇

1、多线程_概念

多线程,简单的来说,就是多任务。
方法间调用:普通方法调用,从哪里来到哪里去,闭合的一条路径。
多线程使用: 开辟了多条路径。

2、多线程_继承Thread

创建线程三种方式:

  • (1)继承Thread
  • (2)实现Runnable接口
  • (3)实现Callable接口(了解即可)
    重点:少用继承,多用实现

你知道三高问题是哪三高吗?
高可用、高性能、高并发

代码敲一敲,你就知道啦。

public class Test1 extends Thread {
	//创建接入口
	@Override
	public void run() {
		for(int i=0;i<20;i++) {
			System.out.println("敲代码");
		}
	}
	public static void main(String[] args) {
		/*
		 * 创建线程方式一:
		 * 继承Thread+重写run
		 */
		//创建子类对象
		Test1 st=new Test1();
		//启动
		st.start();  //不保证立即运行,cpu调用
//		st.run(); //方法调用
		for(int i=0;i<20;i++) {
			System.out.println("学习中");
		}
	}
}

3、多线程_图片下载

知道利用多线程实现网上图片的下载,也是必备的小技巧!

/*
 * 下载图片
 */
public class Test2 {
	public void download(String url,String name) {
		try {
			FileUtils.copyURLToFile(new URL(url),new File(name));
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
			System.out.println("不合法的url!");
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("下载失败!");
		}
	}
}
public class TDownloader extends Thread {
	private String url;  //远程路径
	private String name;  //存储路径
	
	public TDownloader(String url, String name) {
		this.url = url;
		this.name = name;
	}
	@Override
	public void run() {
		Test2 wd=new Test2();
		wd.download(url,name);
		System.out.println(name);
	}
	public static void main(String[] args) {
		TDownloader td1=new TDownloader("图片网址","p1.jpg");
		TDownloader td2=new TDownloader("图片网址","p2.jpg");
		TDownloader td3=new TDownloader("图片网址","p3.jpg");
		
		//启动三个线程
		td1.start();
		td2.start();
		td3.start();
	}
}

学了就去试试吧

4、多线程_实现Runnable

看到实现,你应该想到啥?
没错,就是接口!

/*
 * 实现Runnable
 */
public class Test3 implements Runnable {
	/*
	 * 线程接入点
	 */
	@Override
	public void run() {
		for(int i=0;i<20;i++) {
			System.out.println("敲代码");
		}
	}
	public static void main(String[] args) {
		new Thread(new Test3()).start();
		for(int i=0;i<20;i++) {
			System.out.println("听歌中");
		}
	}
}

5、多线程_抢票_龟兔赛跑

学习了多线程,不拿来展示它的作用也是没得用的,此次就以大家最熟悉的龟兔赛跑和抢票问题来实现吧。

1)模拟购票

public class Test4 implements Runnable{
	//票数
	private int tickets=99;
	@Override
	public void run() {
		while(true) {
			if(tickets<0) {
				break;
			}
			System.out.println(Thread.currentThread().getName()+"-->"+tickets--);
		}
	}
	public static void main(String[] args) {
		//一份资源
		Test4 web1=new Test4();
		//多个代理
		new Thread(web1,"程序员").start();
		new Thread(web1,"码农").start();
		new Thread(web1,"开发工程师").start();
	}
}

2)模拟龟兔赛跑

/*
 * 模拟龟兔赛跑
 */
public class Test5 implements Runnable{
	private static String winner;  //胜利者
	@Override
	public void run() {
		for(int steps=1;steps<=100;steps++) {
			//模拟休息
			if(Thread.currentThread().getName().equals("rabbbit")&&steps%100==0) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName()+"-->"+steps);
			//比赛是否结束
			boolean flag=gameOver(steps);
			if(flag) {
				break;
			}
			
		}
	}
	private boolean gameOver(int steps) {
		if(winner!=null) {  //存在胜利者
			return true;
		}else {
			if(steps==100) {
				winner=Thread.currentThread().getName();
				System.out.println("winner ==>"+winner);
				return true;
			}
		}
		return false;
	}
	public static void main(String[] args) {
		Test5  racer=new Test5();
		new Thread(racer,"tortoise").start();
		new Thread(racer,"rabbit").start();
	}
}

6、多线程_了解Callable

实现Callable步骤:

  • 1、创建目标对象
  • CDownloader cd=new CDownloader(“图片地址”,“baidu.png”)
    //CDownloader类名
  • 2、创建执行服务
    ExecutorService ser=Excutors.newFixedThreadPool(1);
  • 3、提交执行:Future res=ser.submit(cd1);
  • 4、获取结果:boolean r1=res.get();
  • 5、关闭服务:ser.shutdownNow();

7、多线程_静态代理设计模式

/*
 * 静态代理:
 * 接口:
 * 1、真实角色
 * 2、代理角色
 */
public class Test6 {
	public static void main(String[] args) {
		new WeddingCompany(new You()).happy();
		//new Thread(线程对象).start()
	}
}
interface Marry{
	void happy();
}
class You implements Marry{

	@Override
	public void happy() {
		System.out.println("You and ");
	}
}
//代理角色
class WeddingCompany implements Marry{
	//真实角色
	private Marry target;
	public WeddingCompany(Marry target) {
		this.target=target;
	}
	@Override
	public void happy() {
		ready();
		this.target.happy();
		after();
	}
	private void ready() {
		System.out.println("布置");
	}
	private void after() {
		System.out.println("开始");
	}
}

8、多线程_Lambada_简化线程

public class TestLambda {
	//静态内部类
	static class Test implements Runnable{
		public void run() {
			for(int i=0;i<20;i++) {
				System.out.println("敲代码");
			}
		}
	}
	public static void main(String[] args) {
		//静态内部类
//		new Thread(new Test()).start();
		//局部内部类
		class Test2 implements Runnable{
			public void run() {
				for(int i=0;i<20;i++) {
					System.out.println("敲代码");
				}
			}
		}
		//局部内部类
//		new Thread(new Test2()).start();
		//匿名内部类
		new Thread(new Runnable() {
			public void run() {
				for(int i=0;i<20;i++) {
					System.out.println("敲代码");
				}
			}
		}).start();
		//jdk8简化 lambda 用于简化简单的线程 只能推导一个方法
		new Thread(()->{
			for(int i=0;i<20;i++) {
				System.out.println("敲代码");
			}
		}).start();
		
	}
}

温馨提示: lambda :可以带参数,一句的可以省写花括号,类型名(多个参数也行)也可省写

9、多线程_终止

public class Test7 implements Runnable{
	//加入标志 标记线层体是否可以运行
	private boolean flag=true;
	private String name;
	public Test7(String name) {
		this.name=name;
	}
	
	@Override
	public void run() {
		int i=0;
		//关联标志 true-->运行  false-->停止
		while(flag) {
			System.out.println(name+"-->"+i++);
		}
	}
	//3、对外提供方法改变标志
	public void Test7() {
		this.flag=false;
	}
	public static void main(String[] args) {
		Test7 tt=new Test7("xiaoha");
		new Thread(tt).start();
		for(int i=0;i<99;i++) {
			if(i==88) {
				tt.Test7();
				System.out.println("game Over");
			}
			System.out.println("main-->"+i);
		}
		
	}
}

10、多线程_暂停sleep

案例:12306购票、龟兔赛跑
自己动手去实现吧

11、多线程_礼让yield

知识点:yield 礼让线程 暂停线程 直接进入就绪状态 不是阻塞状态

public class TestYield {
	public static void main(String[] args) {
		MyYield my=new MyYield();
		new Thread(my,"a").start();
		new Thread(my,"b").start();
	}
}
class MyYield implements Runnable{

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+"-->start");;
		Thread.yield();
		System.out.println(Thread.currentThread().getName()+"-->end");;
	}
	
}

12、多线程_插队join

知识点:join:合并线程 插队线程

public class TestJoin {
	public static void main(String[] args) {
		System.out.println("爸爸和儿子买烟的故事");
		new Thread(new Father()).start();
	}
}
class Father extends Thread{
	public void run() {
		System.out.println("想抽烟,发现没了");
		System.out.println("让儿子去买烟");
		Thread t=new Thread(new Son());
		t.start();
		try {
			t.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("老爸接过烟,把零钱给了他");
	}
}
class Son extends Thread{
	public void run() {
		System.out.println("接过老爸的钱。。");
		System.out.println("路边有个游戏机,玩了一会");
		for(int i=0;i<10;i++) {
			System.out.println(i+"秒过去了");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("赶紧买烟去。。");
		System.out.println("手拿一包烟回家了..");
	}
}

13、多线程_深度观察状态

知识点:阻塞状态:sleep、join、wait、read、write

public class AllState {
	public static void main(String[] args) {
		Thread tt=new Thread(()->{
			for(int i=0;i<5;i++) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(".....");
		});
		//观察状态
		State state=tt.getState();
		System.out.println(state);  //NEW
		
		tt.start();
		state=tt.getState();  //RUNNING
		while(state!=Thread.State.TERMINATED) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			state=tt.getState();
			System.out.println(state);  //TIMED_WAITING
		}
	}
}

14、多线程_优先级

  • 1、NORM_PRIORITY
  • 2、MIN_PRIORITY
  • 3、MAX_PRIORITY
  • 概率,不代表绝对的先后顺序
public class TestPriority {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getPriority());
		MyPriority mp=new MyPriority();
		Thread t1=new Thread(mp,"红双喜");
		Thread t2=new Thread(mp,"回力");
		Thread t3=new Thread(mp,"NIKE");
		Thread t4=new Thread(mp,"李宁");
		t1.setPriority(Thread.NORM_PRIORITY);
		t2.setPriority(Thread.MIN_PRIORITY);
		t3.setPriority(Thread.MAX_PRIORITY);
		t4.setPriority(Thread.MIN_PRIORITY);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
class MyPriority implements Runnable {

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
	}
	
}

15、多线程_守护线程

知识点:守护线程:是为用户线程服务的;jvm停止不用等待守护线程执行完毕

public class Test8 {
	public static void main(String[] args) {
		God god=new God();
		Ni you=new Ni();
//		new Thread(god).start();
		Thread t=new Thread(god);
		t.setDaemon(true);  //将用户线程调整为守护
		t.start();
		new Thread(you).start();
	}
}
class Ni implements  Runnable{
	@Override
	public void run() {
		for(int i=0;i<=365*100;i++) {
			System.out.println("happy life");
		}
		System.out.println("hahaah");
	}
}
class God implements Runnable{
	@Override
	public void run() {
		for(;true;) {
			System.out.println("belss you");
		}
	}
}

16、多线程_基本信息_网红思维

  • isAlive:线程是否还活着
  • Thread.currentThread():当前线程
  • setName、getName:代理名称
public class Test9 {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().isAlive());  //-->true
		
		//设置名称:真实角色+代理角色
		MyInfo info=new MyInfo("奥迪");
		Thread t=new Thread(info);
		t.setName("奔驰");
		t.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(t.isAlive());  //-->false
		
	}
}
class MyInfo implements Runnable{
	private String name;
	public MyInfo(String name) {
		this.name=name;
	}
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+name);
	}
}

17、多线程_并发_非同步_三大经典案例

  • 线程不安全:数据有负数、相同的情况
  • 线程不安全:取钱
public class UnsafeTest1 {
	public static void main(String[] args) {
		//账户
		Account account=new Account(100,"结婚礼金");;
		Drawing you=new Drawing(account,80,"可爱的你");
		Drawing wife=new Drawing(account,90,"happy");
		you.start();
		wife.start();
		
	}
}
//账户
class Account{
	int money;  //金额
	String name; //名称
	public Account(int money,String name) {
		this.money=money;
		this.name=name;
	}
	
}
//模拟取款
class Drawing extends Thread{
	Account account;  //取钱账户
	int drawingMoney; //取得钱数
	int drawingTotal; //取得总数
	int packetTotal;  //口袋的总数
	public Drawing(Account account, int drawingMoney,String name) {
		super(name);
		this.account = account;
		this.drawingMoney = drawingMoney;
	}
	@Override
	public void run() {
		if(account.money-drawingMoney<0){
			return ;
		}
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		account.money-=drawingMoney;
		packetTotal+=drawingMoney;
		System.out.println(this.getName()+"-->"+"账户的余额为:"+account.money);
		System.out.println(this.getName()+"-->"+"口袋的钱为:"+packetTotal);
	}
	
}

18、多线程_并发_同步_队列与锁

  • 线程安全:在并发时保证数据的正确性、效率尽可能高
  • synchronize

19、多线程_并发_同步_synchronized同步块

  • synchronized():锁定正确的对象
  • 操作容器和对象时

20、多线程_并发_同步_性能分析

  • 线程不安全,范围太小锁不住
  • 尽可能锁定合理的范围

21、多线程_并发_同步_快乐影院

 public class TestSyn {
	public static void main(String[] args) {
		Cinema c=new Cinema(20,"比高");
		new Thread(new Customer(c,3),"xiaoda").start();
		new Thread(new Customer(c,2),"xiaoha").start();
	}
}
//顾客
class Customer implements Runnable{
	Cinema cinema;
	int seat;
	
	public Customer(Cinema cinema, int seat) {
		super();
		this.cinema = cinema;
		this.seat = seat;
	}
	
	@Override
	public void run() {
		synchronized (cinema) {
			boolean flag=cinema.bookTickets(seat);
			if(flag) {
				System.out.println("出票成功"+Thread.currentThread().getName()+"--->位置为"+seat);
			}else {
				System.out.println("出票失败"+Thread.currentThread().getName()+"--->位置不够");
			}
		}
		
		
	}
	
}
//影院
class Cinema{
	int available;  //可用的位置
	String name;  //名称
	public Cinema(int available, String name) {
		super();
		this.available = available;
		this.name = name;
	}
	//购票
	public boolean bookTickets(int seat) {
		System.out.println("可用的位置:"+available);
		if(seat>available) {
			return false;
		};
		available-=seat;
		return true; 
	}
}

22、多线程_并发_死锁_产生与解决

  • 死锁:过多的同步可能造成相互不释放资源
  • 从而相互等待,一般发生于同步中持有多个对象的锁
  • 避免:不要在同一个代码块中同时持有多个对象锁
public class TestSyn{
	public static void main(String[] args) {
		MakeUp g1=new MakeUp(1,"qiqi");
		MakeUp g2=new MakeUp(2,"gaga");
		g1.start();
		g2.start();
	}
}
//口红
class LipStick{
	
}
//镜子
class Mirror{
	
}
//化妆
class MakeUp extends Thread{
	static LipStick lipstick=new LipStick();
	static Mirror mirror=new Mirror();
	//选择
	int choice;
	//名字
	String name;
	public MakeUp(int choice, String name) {
		super();
		this.choice = choice;
		this.name = name;
	}
	@Override
	public void run() {
		//化妆
		makeup();
	}
	//相互持有对方的对象锁-->可能造成死锁
	private void makeup() {
		if(choice==0) {
			synchronized (lipstick) {  //获得口红的锁
				System.out.println(this.name+"获得口红");
				//1秒后想拥有镜子
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
//				synchronized (mirror) {
//					System.out.println(this.name+"获得镜子");
//				}
			}	
			synchronized (mirror) {
				System.out.println(this.name+"获得镜子");
			}
		}else {
			synchronized (mirror) {
				System.out.println(this.name+"获得镜子");
				//2秒后想拥有口红
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
//				synchronized (lipstick) {  //获得口红的锁
//					System.out.println(this.name+"获得口红");
//				}	
			}
			synchronized (lipstick) {  //获得口红的锁
				System.out.println(this.name+"获得口红");
			}	
		}
	}
}

23、多线程_并发协作_生产者消费者模型

解决方式一:并发协作模型—>管程法
生产者:负责生产数据的模块。(这里的模块可能是:方法。对象。线程、进程)
消费者:负责处理数据的模块。(这里的模块可能是:方法。对象。线程、进程)
缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区

解决方式二:并发协作模型—>信号灯法

24、多线程_并发协作_管程法

  • 协作模型:生产者消费者—>管程法
  • 建一个缓冲区
public class TestCusPro {
	public static void main(String[] args) {
		SynContainer container=new SynContainer();
		new Producer(container).start();
		new Customer(container).start();
		
	}
}
//生产者
class Producer extends Thread{
	SynContainer container;
	public Producer(SynContainer container) {
		this.container=container;
	}
	public void run() {
		//生产
		for(int i=0;i<100;i++){
			System.out.println("生产"+i+"个商品");
			container.push(new Goods(i));
		}
		
	}
}
//消费者
class Customer extends Thread{
	SynContainer container;
	public Customer(SynContainer container) {
		this.container=container;
	}
	public void run() {
		//消费
		for(int i=0;i<100;i++) {  //1000改成100,不然一直在等待
			System.out.println("消费"+container.pop().id+"个商品");
			
		}
	}
}
//缓冲区
class SynContainer{
	Goods[] goods=new Goods[10]; //存储容器
	int count=0;  //计数器
	//存储 生产
	public synchronized void push(Goods good) {
		//何时能生产 容器存在空间
		//不能生产 只有等待
		if(count==goods.length) {
			try {
				this.wait();  //线程阻塞 消费者通知生产解除
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//存在空间 可以生产
		goods[count]=good;
		count++;
		//存在数据 可以通知消费了
		this.notifyAll();
	}
	//获取 消费
	public synchronized Goods pop() {
		//何时消费 容器中是否存在数据
		//没有数据 只能等待
		if(count==0) {
			try {
				this.wait();  //线程阻塞 生产者通知消费解除
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//存在数据可以消费
		count--;
		Goods good=goods[count];
		this.notifyAll();  //存在空间,可以唤醒对方生产
		return good;
	}
}
//商品
class Goods{
	int id;

	public Goods(int id) {
		super();
		this.id = id;
	}
	
}

25、多线程_并发协作_信号灯

  • 协作模型:生产者消费者实现方式二:信号灯
  • 借助标志位
public class TestXinhaoDe {
	public static void main(String[] args) {
		TV tv=new TV();
		new Player(tv).start();
		new Listener(tv).start();
	}
}
//生产者 演员
class Player extends Thread{
	TV tv;
	public Player(TV tv) {
		super();
		this.tv = tv;
	}
	public void run() {
		for(int i=0;i<20;i++) {
			if(i%2==0) {
				this.tv.play("music");
			}else {
				this.tv.play("movie");
			}
		}
	}
}
//消费者 观众
class Listener extends Thread{
	TV tv;
	public Listener(TV tv) {
		super();
		this.tv = tv;
	}
	public void run() {
		for(int i=0;i<20;i++) {
			tv.Watch();
		}
	}
}
//同一个资源 电视
class TV{
	String voice;
	//信号灯
	//T 表示演员表演 观众等待
	//F 表示观众观看 演员等待
	boolean flag=true;
	
	//表演
	public synchronized void play(String voice) {
		//演员等待
		if(!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//表演
		System.out.println("表演了"+voice);
		this.voice=voice;
		//唤醒
		this.notifyAll();
		//切换标志
		this.flag=!this.flag;
	}
	//观看
	public synchronized void Watch() {
		//观众等待
		if(flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//观看
		System.out.println("听到了"+voice);
		//唤醒
		this.notifyAll();
		//切换标志
		this.flag=!this.flag;
	}
}

26、多线程_高级主题_定时调度

任务调度:借助Timer和TimerTask类

public class TestTiime {
	public static void main(String[] args) {
		Timer time=new Timer();
		//执行安排
//		time.schedule(new MyTask(),1000); //执行任务一次
//		time.schedule(new MyTask(),1000,200);  //执行多次
		Calendar cal=new GregorianCalendar(2021,12,30,12,30,20);
//		time.schedule(new MyTask(),new Date(5000L),200); //5秒开始
		time.schedule(new MyTask(),cal.getTime(),200);
		
	}
}

//任务类
class MyTask extends TimerTask{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println("休息一会吧");
		}
		System.out.println("-----end------");
	}
}

27、多线程_高级主题_QUARTZ

官网:quartz

28、多线程_高级主题_happenbefore

HappenBefore:执行代码的顺序可能与编写的代码的不一致,即虚拟机优化代码顺序,则为指令重排
数据依赖:

  • (1)写后读 a=1;b=a;
  • (2)写后写:a=1;a=2;
  • (3)读后写:a=b;b=1;
    上面三种情况,只要重排序两个操作的执行顺序,程序的执行结果将会被改变。所以,编译器和处理器在重排序时,会遵守数据依赖性。编译器和处理器不会改变数据依赖关系的两个操作的执行顺序。
/*
 * 指令重排:代码的执行顺序与预期的不一致
 * 目的:提高性能
 */
public class Test {
	//变量1
	private static int a=0; 
	//变量2
	private static boolean flag=false;
	public static void main(String[] args) throws InterruptedException {
		//线程一   更改数据
		Thread t1=new Thread(()->{
			a=1;
			flag=true;
		});
		//线程二   读取数据
		Thread t2=new Thread(()-> {
			if(flag) {
				a*=1;
			}
			//指令重排
			if(a==0) {
				System.out.println("happen before a"+a);
			}
		});
		t1.start();
		t2.start();
		t1.join();
		t2.join();
	}
}

代码有些问题,没得到正确的输出。如果哪位大佬知道哪里有错,欢迎留言评论!

29、多线程_高级主题_volatile

volatile保证线程间的变量的可见性。
目的:为了提高效率
volatile是不错的机制,但是volatile不能保证原子性。

/*
 * volatile:用于保证数据的同步,也就是可见性
 */
public class Testvolatile {
//	private static int num=0;
	private volatile static int num=0; 
	public  static void main(String[] args) throws InterruptedException {
		new Thread(()->{
			while(num==0) {  //此处不要编写代码
				
			}
		}).start();
		Thread.sleep(1000);
		num=1;
	}
}

30、多线程_高级主题_dcl单例模式

dcl单例模式:懒汉式套路的基础上,保证在多线程环境下,对外存在一个对象

  • 1、构造器私有化–>避免外部 new构造器
  • 2、提供私有的静态属性–>存储对象的地址
  • 3、提供公共的静态方法–>获取属性
public class Test1 {
	//2、提供私有的静态属性
	private volatile static Test1 instance;  //避免指令重排
	//没有volatile其他线程可能访问一个没有初始化的对象
	//1、构造器私有化
	private Test1() {
		
	}
	//3、提供公共的静态方法
	public static  Test1 getInstance() {
		//再次检测
		if(null!=instance) {  //避免不必要的同步,已经存在对象
			return instance;
		}
		synchronized (Test1.class) {
			if(null==instance) {
				instance=new Test1();
				//(new做的三件事):1、开辟空间 2、初始化对象信息 3、返回对象的地址给引用
			}
		}
		return instance;
	}
	public static void main(String[] args) {
		Thread t=new Thread(()->{
			System.out.println(Test1.getInstance());
		});
		t.start();
		System.out.println(Test1.getInstance());
	}
}

31、多线程_高级主题_ThreadLocal

ThreadLocal最常用的地方就是为每个线程绑定一个数据库链接,HTTP请求,用户身份信息等。这样一个线程的所有调用到的方法都可以非常方便的访问这些资源。

  • (1)HIbernate的Session 工具类HIbernateUtil
  • (2)通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性。
/*
 * ThreadLoacal:每个线程自身的存储本地。局部区域
 * get/set/initialValue
 */
public class Test3 {
//	private static ThreadLocal threadLocal=new ThreadLocal<>();
	//更改初始值
//	private static ThreadLocal threadLocal=new ThreadLocal<>() {
//		protected Integer initialValue() {
//			return 200;
//		};
//	};
	/*
	 * 方式二:lambda
	 */
	private static ThreadLocal<Integer> threadLocal=ThreadLocal.withInitial(()->200);
	
	
	public static void main(String[] args) {
		//获取值
//		System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //-->main-->null
		System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //-->main-->200
		//设置值
		threadLocal.set(99);
		System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //-->main-->99
	}
	
}

ThreadLocal:分析上下文 环境 起点
1、构造器:哪里调用就属于哪里
2、run方法:本线程自身的

InheritableThreadLocal: 继承上下文 环境的数据 起点 拷贝一份给子线程

32、多线程_高级主题_可重入锁_原理实现

1)可重入锁:锁可以延续使用

public class Test4 {
	public void test() {
		//第一次获得锁
		synchronized (this) {
			while(true) {
				//第二次获得同样的锁
				synchronized (this) {
					System.out.println("ReentrantLock");
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public static void main(String[] args) {
		new Test4().test();
	}
}

2)不可重入锁

public class Test4{
	Lock lock=new Lock();
	public void a() throws InterruptedException {
		lock.lock();
		doSomething();
		lock.unlock();
	}
	//不可重入
	public void doSomething() {
		try {
			lock.lock();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		lock.unlock();
	}
	public static void main(String[] args) throws InterruptedException {
		Test4 test=new Test4();
		test.a();
		test.doSomething();
	}
}
//不可重入锁
class Lock{
	//是否占用
	private boolean isLocked=false;
	//使用锁
	public synchronized void lock() throws InterruptedException {
		while(isLocked) {
			wait();
		}
		isLocked=true;
	}
	//释放锁
	public synchronized void unlock() {
		
	}
}

33、多线程_高级主题_CAS_原子操作

锁分为两类:
(1)悲观锁:synchronized是独占锁即悲观锁,会导致其他所有需要锁的线程挂起,等待持有锁的线程释放锁。
(2)乐观锁:每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试。直到成功为止。

/*
 * CAS:比较并交换
 */
public class CAS {
	//库存
	private static AtomicInteger stock=new AtomicInteger(5); 
	public static void main(String[] args) {
		for(int i=0;i<5;i++) {
			new Thread(()->{
				//模拟网络延时
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				Integer left=stock.decrementAndGet();
				if(left<1) {
					System.out.println("抢完了....");
					return ;
				}
				System.out.println(Thread.currentThread().getName()+"抢了一件商品");
				System.out.println("-->还剩"+left);
			}).start();
		}
	}
}

上篇博文:学习Java_IO_File看这篇就够了

你可能感兴趣的:(Java,eclipse,java,java-ee,c语言,算法)