9、多线程编程

多线程编程

1. 使用方式

通过继承Runnble接口来使用

调用new Thread(this).start;后,会自动执行run()方法里面的内容

2. 线程说明

就绪态:就绪态的资源会主动争夺CUP资源

阻塞态:“睡眠态”,等待被唤醒成为就绪态

  1. 当我们使用new Thread(this).start;后,JVM会创建一个线程执行,此时这个线程会变成“就绪态”,和主线程一块争夺CUP资源,而不是立即执行!

  2. 在多个线程“同时”执行时,计算机系统会为让每一个线程“轮流”执行,也就是说,各个线程会处于“走走停停”的状态(加锁后再议)

  3. synchronized(锁对象):这个锁里面的代码被称为“临界资源”,同一个锁对象锁所锁住的临界资源只能同时被一个线程执行,当线程执行到锁前的时候,会去检查锁的状态:

    • 开:这个线程会进入临界资源,并且会关闭锁
    • 关:这个线程会被阻塞,进入阻塞态

​ 通过锁的使用,可以保证临界资源在被某一个线程调用时,不会被打断,可以完整执行里面的代码,当临界资源执行完毕后,会打开锁,并且会唤醒这个锁对应的被阻塞的线程,然后它们在一起争夺cpu资源

测试样例:

public class ThreadOfGeek implements Runnable{
	
	private static int num;
	private static Object lock = new Object();
	private String threadName;

	public ThreadOfGeek(String threadName) {
		this.threadName = threadName;
		 new Thread(this, threadName).start();;

	}
	
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			synchronized (lock) {
				num += 20;
				num -= 20;
				num++;
				System.out.println(this.threadName +":" + num);
			}	
			for(int j = 0; j < 1000 ; j++) {
				
			}
		}

	}

}
public class TestThread {

	public static void main(String[] args) {
		new ThreadOfGeek("线程A");
		new ThreadOfGeek("线程B");
	}

}

两者都在执行完自己的代码后变成就绪态,与另一方争夺cpu资源,进而可能出现以下的局面

部分结果:

3. wait()和notify()以及notifyAll()

wait():让执行这个方法的线程进入阻塞态

notify():唤醒这个锁对应的某一个处于阻塞态的线程

notifyAll():唤醒这个锁对应的所有处于阻塞态的线程

使用方式:

  • wait方法必须在同步块中调用,并且必须指定锁对象,如:lock.wait();
  • notify和notifyAll方法必须指定锁对象,如:lock.notify();
public class ThreadOfGeek implements Runnable{
	
	private static int num;
	private static Object lock = new Object();
	private String threadName;

	public ThreadOfGeek(String threadName) {
		this.threadName = threadName;
		 new Thread(this, threadName).start();;

	}
	
	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			synchronized (lock) {
				num += 20;
				num -= 20;
				num++;
				System.out.println(this.threadName +":" + num);
				
                //唤醒一个处于lock锁状态的线程
				lock.notify();
				try {
                //将自己变成阻塞态
				lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}	

		}

	}
public class TestThread {

	public static void main(String[] args) {
		new ThreadOfGeek("线程A");
		new ThreadOfGeek("线程B");
	}

}

上面的代码中,先夺取到cpu资源的一个线程执行临界资源代码后,把另一个线程唤醒(因为只有两个线程被lock锁管理)(第一次没有唤醒对方,因为一开始两者都处于就绪态,但是notify方法也可以执行),再把自己阻塞起来,进而完成了A线程和B线程轮流交替进行的局面

posted @   Geek李  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示