java从入门到精通 十八章 多线程

多线程这个概念在经过一段时间的开发后,考虑接口等问题的时候很容易考虑到。比如做电商系统中库存抢购,车票购买的时候如何控制等问题,根本原因就在于一个多线程安全问题,本章提出的解决方法时通过同步代码快的方式,将多线程异步问题 改为多线程同步,这样无论下单的是谁,都是经过一笔一笔单子来处理,这样就不会出现多线程等问题.当然也可以通过消息队列等方式来控制,下单的时候都需要排队,或者通过其他方式实现多线程并发 数据安全等问题.这里暂不做讨论,这里来回顾下多线程的一些概念性问题.

进程/线程的介绍
计算机操作系统中 任务管理器管理多个进程,系统将分配给每一个进程一段cpu时间片,一个进程的时间片执行完毕,执行另一个进程的CPU时间片,因为每一个cpu时间片都非常短,所以看起来就像是 同时在执行多个任务一样.有点像动画的似得,本质就是多个图片组成的动画。只不过感觉不出来而已。而线程就是进程中将系统分配的CPU时间片 再次划分,分配到线程的时间片就更短。

创建线程的2种方式

  1. 创建的线程类实现Runnable接口,实现接口中的run方法,然后通过创建Thread,通过Thread(Runnable target)的构造方法将 线程类实例化,调用Thread的start方法 将线程由创建状态进入就绪状态.
package core.thread;

public class ThreadTest2 implements Runnable {
	int num = 10;

	public void run() {
		while (true) {
			System.out.println(num);
			if (--num == 0) {
				return;
			}
		}
	}

	public static void main(String[] args) {
		new ThreadTest().start();
	}

}

  1. 创建线程类 继承Thread类,重写其中的run方法。然后 通过继承的Thread类的strart()方法,启动线程。同时这个Thread类 实际上是实现Runnable接口的run方法的.
package core.thread;

public class ThreadTest extends Thread {
	int num = 10;

	public void run() {
		while (true) {
			System.out.println(num);
			if (--num == 0) {
				return;
			}
		}
	}

	public static void main(String[] args) {
		new ThreadTest().start();
	}
}

java从入门到精通 十八章 多线程_第1张图片
线程的生命周期
线程从创建到销毁存在7个生命周期.

  1. 创建:线程通过继承Thread或实现Runnable的方式创建类,线程就被创建了
  2. 就绪:线程通start方法 启动线程,线程进入就绪状态,等待CPU时间片分配进入运行状态.
  3. 运行:线程分配到cpu时间片,开始执行
  4. 阻塞:线程执行后,等待输入或者输出命令,在此期间为阻塞状态.
  5. 休眠:线程执行sleep方法,进行休眠状态,休眠时间过去了,重新进入就绪状态.
  6. 等待:线程执行wait方法,进行线程等待状态.可以ton过notify唤醒线程
  7. 死亡:线程执行完毕,销毁了。处于死亡状态.

    用一张图就这么表示了.

线程状态切换的方法

  1. 使线程处于就绪状态的方法
    start方法/进程输入输出 执行完毕/sleep线程刚休眠结束/wait线程等待完毕

  2. 线程由就绪状态 进入运行状态的方法
    线程等待调用notify方法线程唤醒/notifyAll唤醒所有的线程(也就是说线程等待完毕 处于就绪状态/如果调用notify时不等待了 直接进入运行状态了 相当于 插队 开挂了)/interrupt线程中断(当一个线程处于就绪状态 直接打断状态)/线程阻塞完毕/线程休眠状态

操作线程的方法

  1. 线程休眠 sleep(Long time); 毫秒为单位 Long类型
  2. 线程加入join(); A线程中的run方法执行join(Thread B)线程,这样就会先执行B线程,然后才执行A线程。类似于插队.
  3. 线程中断.interrupted()之前有个stop方法 不用了.
  4. 线程礼让yield。不保证礼让结果。

线程优先级
从1到10自小而大 优先级一层层提高. 正常的为NORMAL_PRIORITY.最小的为MIN_PRIORITY.最大的为MAX_PRIORITY.优先级越高,相同时间片段下,优先级高的在前面先执行.
java从入门到精通 十八章 多线程_第2张图片
线程同步安全问题
synchornize是控制多线程的最简单的方法,但是仅是在业务量不大的情况下,通过线程同步来防止数据混乱的问题,举个最简单的例子,卖车票在最后一张的时候,如果多个人都下单了,下单之后有一一系列业务数据操作,耗时比较长,虽然可以考虑解耦,但如果网络 性能等问题造成 前一个人下单再判断库存大于0,开始做业务处理 库存-1的操作时,后面一个人也下单 然后库存也大于0 ,开始操作,这样就可能出现库存数量为-1的情况。所以就需要通过synchronzied同步代码块或者同步方法的形式,将多线程通过类似消息队列的方式一次次处理,这样就可以避免线程安全的问题,例子如下.

package core.thread;


public class ThreadSafe implements Runnable {
	int num = 10;// 模拟共享数据

	public void run() {
		while (true) {
			//利用synchronzied同步代码块的方式
			/*synchronized ("") {
				if (num > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException ex) {
						ex.printStackTrace();
					}
					System.out.println("tickets:" + num--);
				}
			}*/
          //利用synchornzied同步方法
			doit();
		}
	}
	
	private  void  doit(){
		synchronized ("") {
			if (num > 0) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				System.out.println("tickets:" + num--);
			}
		}
	}

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

}

运行结果

tickets:10
tickets:9
tickets:8
tickets:7
tickets:6
tickets:5
tickets:4
tickets:3
tickets:2
tickets:1

你可能感兴趣的:(Java)