day12 多线程1.进程与线程 & 2.线程生命周期 & 3.线程同步机制

day12

bigDecimal,用于计算钱的数据类型

多线程

线程与进程

进程

1)执行中的应用程序

2)一个进程可以包含一个或者多个线程

3)一个进程至少要包含一个线程(如main方法)

线程

线程本身是依靠进程(程序)进行

线程是程序中的顺序控制流,只能使用分配给程序(进程)的资源和环境

线程是进程中可以独立执行的最小执行单元

单线程

程序中只存在一个主线程,实际上main就是一个主线程

线程 :进程中所要完成的一个计算过程,也被称为进程的任务

多线程

更好的使用CPU资源,提高程序的计算效率

串行、并发与并行

串行:一个人,顺序地做多个任务

并行:多个人干一件事情,总耗时取决于时长最长的任务

并发:一个人,交替地做多个任务

实现并发

创建一个线程类的四种方法

public class Th1 {
	public static void main(String[] args){
 		//继承Thread创建线程的方法可以直接创建其对象后用对象调用start()方法   
        Workers1 w1 = new Workers1();
        w1.setName("t1");//给线程命名
        w1.start();
        
    	/**实现Runnable,重写run方法创建线程时,只能先创建线程对象再引用start()方法    
        Workers2 w2 = new Workers2();
        Thread t = new Thread(w2);//Thread(Runnable Target)方法
        //Thread t = new Thread(w2,"th2");//用Thread(Runnable Target, String name)方法命名
        t.start();
*/
    }
}

1)继承Thread类:extends Thread

class Workers1 extends Thread{
    public void run(){
       String name = Thread.currentThread().getName();//Thread(类).currentThread()(获取当前线程对象).getName()(当前线程的名字)
        System.out.println(name);
        System.out.println("线程类开始执行");
    }
}

2)实现Rannable接口:implements Runnable

class Workers2 implements Runnable{
    
    public void run(){
       String name = Thread.currentThread().getName();
        System.out.println(name);
        System.out.println("重写runnable接口");
    }
}

3)通过Callable接口和FutureTask对象创建线程

4)通过线程池创建对象

线程生命周期(五种状态)

1)新建状态;线程对象创建之后,即进入新建状态;

2)就绪状态:调用线程对象的start()方法,线程进入就绪状态。表示线程做好准备随时等待CPU调度执行,并不是执行start()该线程就会立即执行;

3)运行状态:cpu开始调度处于就绪状态的线程时,此时线程才开始执行(执行run()方法),即进入运行状态。注意:就绪状态是进入到运行状态的唯一入口,也就是说,线程想进入运行状态执行,就必须处于就绪状态中;
4)阻塞状态:处于运行状态中的线程由于某种原因,暂时放弃对cpu的使用权,停止执行,此时进入阻塞状态。直到其重新进入到就绪状态,才有机会再次呗cpu调用以进入到运行状态

5)死亡状态:线程执行完毕或者因异常退出了run()方法,该线程结束生命周期,线程销毁。(销毁之前还要垃圾回收,结束周期之后不是立即销毁)

阻塞状态

(根据阻塞产生的原因不同)

1.等待阻塞:运行状态中的线程执行Object.wait()方法

2.同步阻塞:线程在获取synchronized内部锁失败(因为锁被其他线程所占用)

3.其他阻塞:通过调用线程的Thread.sleep()、join()方法或者发出I/O请求时,线程会进入到阻塞状态。当sleep()状态超时(sleep休眠结束)、join()等待线程终止或超时、或者I/O处理完毕时,线程重新转入就绪状态

image

sleep wait方法

sleep()让程序等待一段时间再运行,单位是毫秒

for(int i = 0; i < 9; i++){
    try{
       sleep(1000);//线程休眠,单位是毫秒
    }catch(InterruptedException e){
        e.printStackTrace();
    }
 
    System.out.println(i);
}

wait()线程等待,单位是毫秒

for(int i = 0; i < 9; i++){
    try{
        wait(1000);
    }catch(InterruptedException e){
        e.printStackTrace();
    }
    System.out.println(i);
}//非法监视器

wait()和sleep()区别

1)sleep()方法属于Thread类,wait()方法属于Object类

2)sleep()方法表示线程休眠指定的时间,休眠时间结束,线程继续执行,wait()方法表示线程等待,此时的线程会让出CPU资源,直到其他线程通过notify()/notifyAll()方法唤醒该线程

同步机制

多个线程按照一定顺序执行的解决方案

内部锁(Intrinsic Lock)/监听器(Monitor)

同步锁:synchronized关键字

内部锁是一种排他锁,能够保障原子性、可见性和有序性

synchronized可以用来修饰方法以及代码块,它修饰的方法统称为同步方法,修饰静态方法称为同步静态方法,修饰代码块被称为同步代码块

核心:多个线程争用一把锁,谁拿到锁才能调用锁关键字声明的方法

/**
//类锁
 synchronized(类名.class){
}
*/
public class Th1{
    static int count;
	static void add(){
    synchronized(Th1.class){
    	for(int i = 0; i < 50000; i++){
        	count++;
        	System.out.println(count);
    	}
    }
   
}
}

/**
//方法锁

synchronized(this){

}
*/
public class SynDemo04 {
	int money;
	public static void main(String[] args) {
		SynDemo04 synD14 = new SynDemo04();
		Demo worker = new Demo(synD14,"t1");
		Demo worker2 = new Demo(synD14, "t2");
		worker.start();
		worker2.start();
	}
	
	public void add(){
		//对象锁
		synchronized (this) {
			for (int i = 0; i < 50000; i++) {
				money++;
				System.out.println(money);
			}
		}
		
	}
	
	
}

class Demo extends Thread{
	private SynDemo04 synD;
	public Demo(SynDemo04 synD,String name){
		this.synD = synD;
		this.setName(name);
	}
	public void run() {
		synD.add();
	}
}

显式锁:Lock接口

posted @ 2022-10-17 20:49  小彤在努力  阅读(21)  评论(0)    收藏  举报