线程的两种创建方式和三种同步方式

引入
进程:简单的理解进程就是一个应用程序
线程: 就是进程的最小执行单位,是一个独立的功能

多线程作用:
1、为了利用计算机的多核心优势
2、提高程序运行效率

创建方式
一、继承Thread类
步骤:
1、写一个线程类XxxThread extends Thread类
2、重写run()方法
3、写一个测试类,在测试类中创建线程对象—>调用对象的start()启动线程

二、实现Runnable接口
步骤:
1、写一个实现业务类XxxRunnableImpl implements Runnable接口
2、重写run()方法
3、写一个测试类,在测试类中先创建业务类对象—>再通过构造方法创建线程对象(业务类对象)—>调用线程对象的start()启动线程

注意事项:
1、只有继承Thread类的子类才能叫线程类,实现Runnable接口的子类叫业务类
2、启动线程类是两步:创建对象—>对象.start(),
启动业务类是三步:创建业务类对象—>创建线程对象(业务类对象)—>线程对象.start()
3、start()会去执行线程里的run()方法,但只有start()才是启动线程,run()只是在执行方法
在这里插入图片描述

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

同步方式
一、悲观锁(以最坏的情况做打算)
1、同步代码块

synchronized(同步对象){
    
    
		//有线程安全问题的代码;
}
//注意事项:作为同步对象需要满足的条件:只有一份(静态区中的静态成员或元空间中的字节码文件)

2、同步方法
用synchronized关键字修饰方法即可,写在返回值前面,方法体里是有线程安全问题的代码

注意事项:因为创建业务类对象只需要一个,然后通过创建线程类对象来启动
1、若是继承类使用同步代码块,通过同步对象控制共享,所以必须是只有一份的;若是业务类,this即可
2、若是继承类使用同步方法,方法必须要static修饰;若是业务类,就不要求

二、乐观锁
锁机制:Lock接口的实现类ReentrantLock
构造方法:

  1. ReentrantLock() 创建一个 ReentrantLock的实例,获取锁的几率不同
  2. ReentrantLock(boolean fair) 根据给定的公平政策创建一个 ReentrantLock的实例。 理论上获取锁的几率是相同的
class X {
    
    
	//1.创建一个 ReentrantLock的实例。不要公平机制,效率高
	private final ReentrantLock lock = new ReentrantLock();

	/**
	* 在run()中进行调用
	*/
	public void m() {
    
    
	    lock.lock();  // 上锁
	     try {
    
    
	       	//有线程安全问题的代码
	     } finally {
    
    
	       lock.unlock();//释放锁,不然后面其他线程无法执行代码
	     }
	}
}

注意事项:
1、悲观锁和乐观锁是一个总称,不仅仅包括这三种方法
2、锁原则:最小范围原则(锁住的代码块最小化),为了保证执行效率,锁机制效率高且功能更加强大,建议使用
3、同步方法最简单,如果能够满足性能要求,建议使用同步方法

==============================================================
经典案例:多窗口售票(继承类+代码块)
案例描述:总票数:50,三个窗口同时售卖

继承类:

public class SaleTicketTread extends Thread {
    
    
	private static int ticket=50;

	public SaleTicketTread() {
    
    
		super();
	}
	
	/**
	 * 给线程起名,为了打印看输出方便
	 * @param name
	 */
	public SaleTicketTread(String name) {
    
    
		super(name);
	}

	@Override
	public void run() {
    
    
		while (ticket>0) {
    
    
			sale();
		}
	}

	private void sale() {
    
    
		synchronized (SaleTicketTread.class) {
    
    //只有一份的对象
			if (ticket>0) {
    
    //虽然锁住了,但是还是会出现多个线程同时进入run,ticket未--,所以在下一个线程执行售票之前,先判断ticket是否卖光
				System.out.println(Thread.currentThread().getName()+",票号:"+ticket);
				ticket--;
			}
		}
	}
}

测试类

public class TicketTest {
    
    

	public static void main(String[] args) {
    
    
		SaleTicketTread ticket1= new SaleTicketTread("窗口1");
		SaleTicketTread ticket2= new SaleTicketTread("窗口2=====");
		SaleTicketTread ticket3= new SaleTicketTread("窗口3=========");
		
		ticket1.start();
		ticket2.start();
		ticket3.start();
	}
}

问题代码分析:为何需要if (ticket>0)
在这里插入图片描述

おすすめ

転載: blog.csdn.net/ExceptionCoder/article/details/107557722