1、JUC系列之---线程基础

∥☆過路亽.° 提交于 2020-02-29 17:22:03

一、多线程概述

1、进程:正在进行中的程序
2、线程:就是进程中一个负责程序执行的控制单元(执行路径)

一个进程中,可以有多个执行路径,即多线程

一个进程中,至少有一个执行路径。

(多线程其实就是多个线程中的快速切换)

二、多线程的创建方式①--继承Thread类

继承Thread类,重写run方法

1、JVM创建的主线程的任务都定义在了主函数中

2、Thread类中的run方法就是封装自定义线程任务的函数,即run方法相当于一个main方法

package com.lee.juc;

public class ThreadDemo_01 {

	public static void main(String[] args) {
		Demo demo1 = new Demo("张三");
		Demo demo2 = new Demo("LeeSi");
		
		demo1.start();
		demo2.start();
		System.out.println("=======结束========");
	}
	
}

class Demo extends Thread{
	private String name;

	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(name+"====>"+i);
		}
	}
	
	public Demo() {
		super();
	}
	public Demo(String name) {
		this.name = name;
	}
}

结果:

================================

注:调用Run和Start有什么区别?

 

================================

方法:

getName  获取线程名称

CurrentThread  返回当前正在执行线程的引用对象

三、多线程的创建方式②--实现Runnable接口

package com.lee.juc;

public class ThreadDemo_02 {

	public static void main(String[] args) {
		
		Demo2 d = new Demo2();
		
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		
		t1.start();
		t2.start();
		
	}
}

class Demo2 implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(i+"====>"+Thread.currentThread().getName());
		}
	}
}

结果:

===========================

注:通过implement Runnable接口的方法 

避免了单继承 extends Thread的局限性

===========================

 

四、线程状态

再增加一个临时阻塞状态

五、卖票小程序

需求:四个窗口共同卖100张票

1、继承Thread方法

NUM为static

package com.lee.juc;

public class TicketDemo_01 {

	public static void main(String[] args) {
		
		Ticket_01 t1 = new Ticket_01();
		Ticket_01 t2 = new Ticket_01();
		Ticket_01 t3 = new Ticket_01();
		Ticket_01 t4 = new Ticket_01();
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_01 extends Thread{

	private static int NUM = 100;
	
	@Override
	public void run() {
		while(true) {
			if(NUM>0) {
				System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
			}else {
				break;
			}
		}
	}
	
}

结果:

2、实现Runnable接口

package com.lee.juc;

public class TicketDemo_02 {

	public static void main(String[] args) {
		Ticket_02 ticket = new Ticket_02();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		Thread t3 = new Thread(ticket);
		Thread t4 = new Thread(ticket);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_02 implements Runnable{

	private int NUM = 100;
	
	@Override
	public void run() {
		while(true) {
			if(NUM>0) {
				System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
			}else {
				break;
			}
		}
	}
	
}

结果:

六、线程安全问题现象

package com.lee.juc;

public class TicketDemo_03 {

	public static void main(String[] args) {
		Ticket_03 ticket = new Ticket_03();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		Thread t3 = new Thread(ticket);
		Thread t4 = new Thread(ticket);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_03 implements Runnable{

	private int NUM = 100;
	
	@Override
	public void run() {
		while(true) {
			
			if(NUM>0) {
				
                //======加sleep=======
				try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
				
				System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
				
			}else {
				break;
			}
		}
	}
	
}

结果:

产生原因:

①、多个线程,操作同一个共享数据

②、操作共享数据的线程代码有多条

七、同步代码块

就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算。

必须要当前线程把这些代码都执行完后,其他线程才能执行。

同步代码块的格式:

synchronized(对象){

     需要被同步的代码;

}

代码:

package com.lee.juc;

public class TicketDemo_03 {

	public static void main(String[] args) {
		Ticket_03 ticket = new Ticket_03();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		Thread t3 = new Thread(ticket);
		Thread t4 = new Thread(ticket);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}

class Ticket_03 implements Runnable{

	private int NUM = 100;

	Object obj = new Object();  	

	@Override
	public void run() {
		while(true) {
            //====================
			synchronized (obj) {
				if(NUM>0) {
					try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
					System.out.println(Thread.currentThread().getName()+"...sale.."+NUM--);
				}else {
					break;
				}
			}
            //=====================
			
		}
	}
	
}

结果:

同步的好处和弊端:

好处:解决了线程安全的问题

弊端:相对降低了效率

注:

必须保证多个线程使用同一个锁

八、同步函数

需求:

两个储户去银行存钱,每个人存3次,每次存¥100

1、未加锁的错误代码

package com.lee.juc;

public class BankDemo_01 {

	public static void main(String[] args) {
		Customer cus = new Customer();
		
		Thread t1 = new Thread(cus);
		Thread t2 = new Thread(cus);
		
		t1.start();
		t2.start();
	}
}

class Bank{
	private int SUM;
	
	public void add(int num) {
		SUM = SUM +num;
		System.out.println("current bank count money : ==>"+SUM);
	}
}

class Customer implements Runnable{

	//两人公用一个bank,所以bank提出来
	private Bank bank = new Bank();
	
	@Override
	public void run() {
		for(int i=0;i<3;i++) {
			bank.add(100);
		}
	}
	
}

2、加锁,正确代码

package com.lee.juc;

import org.omg.Messaging.SyncScopeHelper;

public class BankDemo_01 {

	public static void main(String[] args) {
		Customer cus = new Customer();
		
		Thread t1 = new Thread(cus);
		Thread t2 = new Thread(cus);
		
		t1.start();
		t2.start();
	}
}

class Bank{
	private int SUM;
	
	public void add(int num) {
		SUM = SUM +num;
		System.out.println("current bank count money : ==>"+SUM);
	}
}

class Customer implements Runnable{

	//两人公用一个bank,所以bank提出来
	private Bank bank = new Bank();
	
	@Override
	public void run() {
		for(int i=0;i<3;i++) {
			//===========加锁
			synchronized(bank) {
				bank.add(100);
			}
            //============
		}
	}
	
}

或者

package com.lee.juc;

public class BankDemo_01 {

	public static void main(String[] args) {
		Customer cus = new Customer();
		
		Thread t1 = new Thread(cus);
		Thread t2 = new Thread(cus);
		
		t1.start();
		t2.start();
	}
}

class Bank{
	private int SUM;
	
	//同步函数锁
	public synchronized void add(int num) {
		SUM = SUM +num;
		System.out.println("current bank count money : ==>"+SUM);
	}
}

class Customer implements Runnable{

	//两人公用一个bank,所以bank提出来
	private Bank bank = new Bank();
	
	@Override
	public void run() {
		for(int i=0;i<3;i++) {
			bank.add(100);
		}
	}
	
}

结果:

九、验证同步函数的锁

1、验证是否是Object

package com.lee.juc;

public class TicketDemo_04 {

	public static void main(String[] args) {
		Ticket_04 ticket = new Ticket_04();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		ticket.flag = false;
		t2.start();
		
	}
}

class Ticket_04 implements Runnable{

	private int NUM = 100;
	boolean flag = true;

	Object obj = new Object();  	

	@Override
	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (obj) {
					if(NUM>0) {
						try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"......同步代码块....."+NUM--);
					}
				}
			}
		}else {
			while(true) {
				this.sale();
			}
		}
		
	}
	
	public synchronized void sale() {
		if(NUM>0) {
			try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"...同步函数.."+NUM--);
		}
	}
	
}

结果:

错误,证明不是obj

2、证明是不是this

package com.lee.juc;

public class TicketDemo_04 {

	public static void main(String[] args) {
		Ticket_04 ticket = new Ticket_04();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		ticket.flag = false;
		t2.start();
		
	}
}

class Ticket_04 implements Runnable{

	private int NUM = 100;
	boolean flag = true;

	Object obj = new Object();  	

	@Override
	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (this) {
					if(NUM>0) {
						try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"......同步代码块....."+NUM--);
					}
				}
			}
		}else {
			while(true) {
				this.sale();
			}
		}
		
	}
	
	public synchronized void sale() {
		if(NUM>0) {
			try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"...同步函数.."+NUM--);
		}
	}
	
}

结果:

证明是this

十、验证静态同步函数的锁

代码:

package com.lee.juc;

public class TicketDemo_05 {

	public static void main(String[] args) {
		Ticket_05 ticket = new Ticket_05();
		
		Thread t1 = new Thread(ticket);
		Thread t2 = new Thread(ticket);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		ticket.flag = false;
		t2.start();
		
	}
}

class Ticket_05 implements Runnable{

	private static int NUM = 100;
	boolean flag = true;

	Object obj = new Object();  	

	@Override
	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (this.getClass()) {
					if(NUM>0) {
						try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"......同步代码块....."+NUM--);
					}
				}
			}
		}else {
			while(true) {
				this.sale();
			}
		}
		
	}
	
	public static synchronized void sale() {
		if(NUM>0) {
			try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"...同步函数.."+NUM--);
		}
	}
	
}

结果:

注:

静态同步函数的锁是  当前文件的字节码,this.getClass或TicketDemo_05.class

十一、单例模式

//懒汉式
class SingleLazy{
	private static SingleLazy singleLazy;
	
	private SingleLazy() {}
	
	private static SingleLazy getInstance() {
		
		if(singleLazy==null) {
			synchronized (SingleLazy.class) {
				if(singleLazy==null) {
					singleLazy = new SingleLazy();
				}
			}
		}
		
		return singleLazy;
	}
	
}

//饿汉式--推荐使用这个
class SingleHungry{
	
	private static SingleHungry singleHungry = new SingleHungry();
	
	private SingleHungry() {}
	
	private static SingleHungry getInstance() {
		return singleHungry;
	}
	
}

十二、死锁的情景

产生情景:

1、同步的嵌套:A锁里边有B锁,B锁里边有A锁。

package com.lee.juc;

public class DeadLockTest {

	public static void main(String[] args) {
		DeadLock deadLock = new DeadLock();//flag = true
		
		Thread t1 = new Thread(deadLock);
		Thread t2 = new Thread(deadLock);
		
		t1.start();
		try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
		deadLock.flag = false;
		t2.start();
		
	}
	
}

class DeadLock implements Runnable{
	
	public boolean flag = true;
	private Object obj = new Object();
	
	public DeadLock() {}
	
	public DeadLock(boolean flag) {
		this.flag = flag;
	}

	public void run() {
		
		if(flag) {
			while(true) {
				synchronized (this) {
					System.out.println("...if...this...lock.."+Thread.currentThread().getName());
					synchronized (obj) {
						System.out.println("...if...obj...lock.."+Thread.currentThread().getName());
					}
				}
			}
			
		}else {
			
			while(true) {
				synchronized (obj) {
					System.out.println("...else...obj...lock.."+Thread.currentThread().getName());
					synchronized (this) {
						System.out.println("...else...this...lock.."+Thread.currentThread().getName());
					}
				}
			}
			
		}
		
		
	}
	
}

结果:

   

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!